Skip to content
This repository has been archived by the owner on Jul 4, 2022. It is now read-only.

crcn/tandem-old

Repository files navigation

License Chat

⚠️ This is a pre-release, so expect a few bugs and missing features!

Resources

Build UIs in real-time ⚡️

Paperclip is a template language that's designed for visual development. See what you're creating in real-time, directly within VS Code.

VSCode Demo

What is Paperclip exactly?

Paperclip just covers basic HTML, CSS, and syntax for defining dumb components. Here's an example:

<!-- todo-list.pc -->

<!--
Styles are scoped to this file, so you don't have to worry about them leaking out.
-->

<style>
  * {
    font-family: Helvetica;
  }

  ul {
    list-style-type: none;
    margin: 0;
    padding: 0;
  }
  
  li[done] {
    text-decoration: line-through;
  }
</style>

<!-- Parts are building blocks that are individually used in application code (more information below). -->
<part id="TodoItem">

  <!-- You can assign attribute bindings. -->
  <li {done}>
    <input type="checkbox" checked={done} onClick={onDoneClick}>

    <!-- You can also define slots where text & elements are inserted into. -->
    {label}
  </li>
</part>

<part id="TodoList">
  <h1>Todos:</h1>
  <input type="text" onKeyPress={onNewTodoKeyPress} placeholder="Add a new todo..." >
  <ul>
    {todoItems}
  </ul>
</part>

<!-- Preview is a special tag for development that allows you to see how all of your parts look when put together in their varying states. -->
<preview>
  <TodoList todoItems={<>
    <TodoItem label="Feed cat" done />
    <TodoItem label="Take out trash" />
    <TodoItem label="Walk dog" done />
  </>} />
</preview>

Here's what you see in VS Code as you type away:

Simple todo preview

☝🏻This example uses just about all of the features that Paperclip has to offer. No logic, just syntax for describing how your UI looks.

How do I add logic?

Templates compile directly to highly optimized code. Using our list example above, here's how you might use it in a React app:

// <part /> elements are exposed as React components.
import { TodoList, TodoItem } from "./list.pc";
import React, { useState } from "react";

export default () => {
  const [todos, setTodos] = useState([
    { label: "Clean car" },
    { label: "Eat food", done: true },
    { label: "Sell car" }
  ]);

  const onNewInputKeyPress = (event) => {
    if (event.key === "Enter" && value) {
      setTodos([...todos, { label: event.target.value }]);
      event.target.value = "";
    }
  };

  const onDoneClick = (todo: Todo) => {
    setTodos(
      todos.map(oldTodo => {
        return oldTodo.id === todo.id
          ? {
              ...oldTodo,
              done: !oldTodo.done
            }
          : oldTodo;
      })
    );
  };

  // The attribute bindings & slots that were defined are
  // exposed as props for each <part /> component.
  return (
    <TodoList
      onNewTodoKeyPress={onNewInputKeyPress}
      todoItems={todos.map(todo => {
        return (
          <TodoItem
            done={todo.done}
            onDoneClick={() => onDoneClick(todo)}
            label={todo.label}
            key={todo.id}
          />
        );
      })}
    />
  );
};

The code for this example is also here.

More compiler targets are planned for other languages and frameworks. React is just a starting point ✌🏻.

As you can see, <part /> elements are exported as dumb components that React can use. From there we can combine all parts with logic to create a functional component. That's the gist of Paperclip!

Strongly Typed 🦺

Templates compile down to strongly typed code, so you don't have to guess about what your templates need. Here's a generated TypesScript definition of our React app above:

import {ReactNode, ReactHTML, Factory, InputHTMLAttributes, ClassAttributes} from "react";

type ElementProps = InputHTMLAttributes<HTMLInputElement> & ClassAttributes<HTMLInputElement>;

export declare const styled: (tag: keyof ReactHTML | Factory<ElementProps>, defaultProps?: ElementProps) => Factory<ElementProps>;

type TodoItemProps = {
  done: String | boolean | Number | Object | ReactNode,
  onDoneClick: Function,
  label: String | boolean | Number | Object | ReactNode,
};

export const TodoItem: Factory<TodoItemProps>;

type TodoListProps = {
  onNewTodoKeyPress: Function,
  todoItems: String | boolean | Number | Object | ReactNode,
};

export const TodoList: Factory<TodoListProps>;

Features ✨

  • Works out of the box. Just download the VS Code extension and start typing away.
  • Previews are powered by a low-level runtime, so your changes appear instantly, and won't slow down as your project scales.
  • Templates can be compiled to strongly typed code.
  • Templates Integrate with your existing React application (more languages & frameworks soon).
  • Integrates with Webpack.

Roadmap 🌄

This is just the beginning! Here are just a few planned features:

  • Zero-setup automated visual regression testing. Just plug in your Paperclip files.
  • More compiler targets: Ruby, PHP, VueJS, AngularJS, and others.
  • More code editor integrations: Sublime, Atom.
  • More visual tooling in the preview, so you can make visual changes directly.
  • Preview against different browsers directly within your code editor.
  • Animation tooling

Goals 🎯

The goal for Paperclip is to eliminate bottlenecks around HTML & CSS development, and provide tooling that helps you ship UI features quicker. More specifically:

  • Eliminate the lag time between writing code & seeing UI.
  • Shorten the gap between design -> code by bringing more design tooling into web development.
  • Provide better safety around building UIs with easier to use cross-browser testing tools.

About

Live web development directly within VS Code

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •