Skip to content

Commit

Permalink
Add Marko (#149)
Browse files Browse the repository at this point in the history
* WIP: add Marko

* WTF, vscode

* Consistent final newlines

* Apply suggestions from code review

Everything except for the TS declarations since I think Dylan ought to weigh in

Co-authored-by: Michael Rawlings <[email protected]>
Co-authored-by: Luke LaValva <[email protected]>

* Feedback: no space before method parens, no TS, else-if, ColorSelect works now

* Pre-bugbash updates

* This is probably why they want us to provide a linter

* Finishing touches

* Argle

* @rturnq feedback

* Match examples to other frameworks

---------

Co-authored-by: Michael Rawlings <[email protected]>
Co-authored-by: Luke LaValva <[email protected]>
Co-authored-by: tigt <[email protected]>
  • Loading branch information
4 people authored Apr 3, 2023
1 parent 11975c8 commit a01e903
Show file tree
Hide file tree
Showing 39 changed files with 399 additions and 13 deletions.
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
# 🧑‍💻 Contributing

This site is built with [Astro](https://docs.astro.build). Site content is written in Markdown format located in `content`. For simple edits, you can directly edit the file on GitHub and generate a Pull Request.
This site is built with [Vite](https://vitejs.dev) and [Svelte](https://svelte.dev). Site content is written in Markdown format located in `content`. For simple edits, you can directly edit the file on GitHub and generate a Pull Request.

## Add a framework

1. Fork the project and create a new branch
2. Add the new framework SVG logo in `public/framework`
3. Install the ESLint plugin associated to the framework
4. In `frameworks.mjs`, add a new entry with SVG link and ESLint configuration
5. If the framework needs a language syntax highlight, add it to the call to `getHighlighter`’s `langs` argument in `build/lib/generateContent.js`
6. To make a playground link:
1. Add a `create${FRAMEWORK}Playground.js` file in `build/lib/playground`.
2. That file should export a function that returns an object with a `fromContentByFilename` method that accepts an object of filepath keys and file content values, then returns an absolute URL to a framework’s online REPL with those files loaded.
3. Register its export in `build/lib/playground/index.js`

## Improve website

Expand Down
64 changes: 53 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/svelte.svg" />
<b>Svelte</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100" /></summary>
<img alt="100% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -52,7 +52,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/react.svg" />
<b>React</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100" /></summary>
<img alt="100% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -89,7 +89,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/vue.svg" />
<b>Vue 3</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/96" /></summary>
<img alt="96% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/96" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -126,7 +126,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/solid.svg" />
<b>SolidJS</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>
<img alt="92% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -163,7 +163,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/qwik.svg" />
<b>Qwik</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>
<img alt="92% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -200,7 +200,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/angular.svg" />
<b>Angular</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>
<img alt="92% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -237,7 +237,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/lit.svg" />
<b>Lit</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/96" /></summary>
<img alt="96% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/96" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -274,7 +274,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/vue.svg" />
<b>Vue 2</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100" /></summary>
<img alt="100% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -311,7 +311,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/ember.svg" />
<b>Ember</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>
<img alt="92% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -348,7 +348,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/alpine.svg" />
<b>Alpine</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/96" /></summary>
<img alt="96% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/96" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -385,7 +385,7 @@ How do we solve this ? Developers love having framework overview by examples. It
<summary>
<img width="18" height="18" src="public/framework/aurelia.svg" />
<b>Aurelia 1</b>
<img src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>
<img alt="92% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/92" /></summary>

- [x] Reactivity
- [x] Declare state
Expand Down Expand Up @@ -418,6 +418,43 @@ How do we solve this ? Developers love having framework overview by examples. It
- [x] Router link
- [x] Routing

</details><details>
<summary>
<img width="18" height="18" src="public/framework/marko.svg">
<b>Marko</b>
<img alt="100% progress" src="https://us-central1-progress-markdown.cloudfunctions.net/progress/100"></summary>

- [x] Reactivity
- [x] Declare state
- [x] Update state
- [x] Computed state
- [x] Templating
- [x] Minimal template
- [x] Styling
- [x] Loop
- [x] Event click
- [x] Dom ref
- [x] Conditional
- [x] Lifecycle
- [x] On mount
- [x] On unmount
- [x] Component composition
- [x] Props
- [x] Emit to parent
- [x] Slot
- [x] Slot fallback
- [x] Context
- [x] Form input
- [x] Input text
- [x] Checkbox
- [x] Radio
- [x] Select
- [x] Webapp features
- [x] Render app
- [x] Fetch data
- [x] Router link
- [x] Routing

</details>

## 🤝 Contributing
Expand All @@ -439,6 +476,11 @@ This project requires Node.js to be `v16.0.0` or higher.
2. Add the new framework SVG logo in `public/framework`
3. Install the ESLint plugin associated to the framework
4. In `frameworks.mjs`, add a new entry with SVG link and ESLint configuration
5. If the framework needs a language syntax highlight, add it to the call to `getHighlighter`’s `langs` argument in `build/lib/generateContent.js`
6. To make a playground link:
1. Add a `create${FRAMEWORK}Playground.js` file in `build/lib/playground`.
2. That file should export a function that returns an object with a `fromContentByFilename` method that accepts an object of filepath keys and file content values, then returns an absolute URL to a framework’s online REPL with those files loaded.
3. Register its export in `build/lib/playground/index.js`

## 🧑‍💻 Contributors

Expand Down
11 changes: 10 additions & 1 deletion build/lib/generateContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,16 @@ async function pathExists(path) {
export default async function generateContent() {
const highlighter = await getHighlighter({
theme: componentPartyShikiTheme,
langs: ["javascript", "svelte", "html", "hbs", "tsx", "jsx", "vue"],
langs: [
"javascript",
"svelte",
"html",
"hbs",
"tsx",
"jsx",
"vue",
"marko",
],
});

const rootDir = await packageDirectory();
Expand Down
18 changes: 18 additions & 0 deletions build/lib/playground/createMarkoPlayground.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import nodePath from "node:path";
import { compressToURL } from "@matschik/lz-string";

const BASE = "https://markojs.com/playground/#";

export default function createMarkoPlayground() {
return {
fromContentByFilename(contentByFilename) {
const data = Object.entries(contentByFilename).map(([path, content]) => ({
name: nodePath.parse(path).base,
path: `/components/${path}`,
content,
}));

return BASE + compressToURL(JSON.stringify(data));
},
};
}
2 changes: 2 additions & 0 deletions build/lib/playground/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import createAlpinePlayground from "./createAlpinePlayground.js";
import createSveltePlayground from "./createSveltePlayground.js";
import createVue3Playground from "./createVue3Playground.js";
import createSolidPlayground from "./createSolidPlayground.js";
import createMarkoPlayground from "./createMarkoPlayground.js";

export default {
vue3: createVue3Playground(),
svelte: createSveltePlayground(),
alpine: createAlpinePlayground(),
solid: createSolidPlayground(),
marko: createMarkoPlayground(),
};
2 changes: 2 additions & 0 deletions content/1-reactivity/1-declare-state/marko/Name.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<let/name = "John"/>
<h1>Hello ${name}</h1>
3 changes: 3 additions & 0 deletions content/1-reactivity/2-update-state/marko/Name.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<let/name = "John"/>
<effect() { name = "Jane" }/>
<h1>Hello ${name}</h1>
3 changes: 3 additions & 0 deletions content/1-reactivity/3-computed-state/marko/DoubleCount.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<let/count = 10/>
<const/doubleCount = count * 2/>
<div>${doubleCount}</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<h1>Hello world</h1>
14 changes: 14 additions & 0 deletions content/2-templating/2-styling/marko/CssStyle.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<h1.title>I am red</h1>
<button style={ fontSize: "10rem" }>I am a button</button>
<button class=scopedButton>I am a style-scoped button</button>

<style>
.title {
color: red;
}
</style>
<style/{ scopedButton }>
.scopedButton {
font-size: 10rem;
}
</style>
5 changes: 5 additions & 0 deletions content/2-templating/3-loop/marko/Colors.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<ul>
<for|color| of=["red", "green", "blue"]>
<li>${color}</li>
</for>
</ul>
3 changes: 3 additions & 0 deletions content/2-templating/4-event-click/marko/Counter.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<let/count = 0/>
<p>Counter: ${count}</p>
<button onClick() { count++ }>+1</button>
2 changes: 2 additions & 0 deletions content/2-templating/5-dom-ref/marko/InputFocused.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<input/inputElement>
<effect() { inputElement().focus() }/>
14 changes: 14 additions & 0 deletions content/2-templating/6-conditional/marko/TrafficLight.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
static const TRAFFIC_LIGHTS = ["red", "orange", "green"];
<let/lightIndex = 0/>
<const/light = TRAFFIC_LIGHTS[lightIndex]/>

<button onClick() { lightIndex = (lightIndex + 1) % TRAFFIC_LIGHTS.length }>
Next light
</button>
<p>Light is: ${light}</p>
<p>
You must
<if=light === "red">STOP</if>
<else-if=light === "orange">SLOW DOWN</else-if>
<else>GO</else>
</p>
3 changes: 3 additions & 0 deletions content/3-lifecycle/1-on-mount/marko/PageTitle.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<let/pageTitle = ""/>
<effect() { pageTitle = document.title }/>
<p>Page title: ${pageTitle}</p>
6 changes: 6 additions & 0 deletions content/3-lifecycle/2-on-unmount/marko/Time.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<let/time = new Date()/>
<lifecycle
onMount() { this.timer = setInterval(_ => time = new Date(), 1000) }
onDestroy() { clearInterval(this.timer) }
/>
<p>Current time: ${time.toLocaleTimeString()}</p>
6 changes: 6 additions & 0 deletions content/4-component-composition/1-props/marko/App.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<UserProfile
name="John"
age=20
favouriteColors=["green", "blue", "red"]
isAvailable
/>
11 changes: 11 additions & 0 deletions content/4-component-composition/1-props/marko/UserProfile.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<const/{
name = "",
age = null,
favouriteColors = [],
isAvailable = false,
} = input/>

<p>My name is ${name}!</p>
<p>My age is ${age}!</p>
<p>My favourite colors are ${favouriteColors.join(", ")}!</p>
<p>I am ${isAvailable ? "available" : "not available"}</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<button onClick=input.onYes>YES</button>
<button onClick=input.onNo>NO</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<let/isHappy = true/>
<p>Are you happy?</p>
<AnswerButton
onYes() { isHappy = true }
onNo() { isHappy = false }
/>
<p style={ fontSize: 50 }>${isHappy ? "😀" : "😥"}</p>
1 change: 1 addition & 0 deletions content/4-component-composition/3-slot/marko/App.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<FunnyButton>Click me!</FunnyButton>
18 changes: 18 additions & 0 deletions content/4-component-composition/3-slot/marko/FunnyButton.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<button.${funnyButton}>
<${input.renderBody}/>
</button>

<style.module.css/{ funnyButton }>
.funnyButton {
background: rgba(0, 0, 0, 0.4);
color: #fff;
padding: 10px 20px;
font-size: 30px;
border: 2px solid #fff;
margin: 8px;
transform: scale(0.9);
box-shadow: 4px 4px rgba(0, 0, 0, 0.4);
transition: transform 0.2s cubic-bezier(0.34, 1.65, 0.88, 0.925) 0s;
outline: 0;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<FunnyButton/>
<FunnyButton>I got content!</FunnyButton>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<button.${funnyButton}>
<${input.renderBody}>
<span>No content found</span>
</>
</button>

<style.module.css/{ funnyButton }>
.funnyButton {
background: rgba(0, 0, 0, 0.4);
color: #fff;
padding: 10px 20px;
font-size: 30px;
border: 2px solid #fff;
margin: 8px;
transform: scale(0.9);
box-shadow: 4px 4px rgba(0, 0, 0, 0.4);
transition: transform 0.2s cubic-bezier(0.34, 1.65, 0.88, 0.925) 0s;
outline: 0;
}
</style>
13 changes: 13 additions & 0 deletions content/4-component-composition/5-context/marko/App.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<let/user = { // In a real app, you would fetch the user data from an API
id: 1,
username: "unicorn42",
email: "[email protected]",
}/>
<const/updateUsername(newUsername) {
user = { ...user, username: newUsername };
}/>

<h1>Welcome back, ${user.username}</h1>
<set={ ...user, updateUsername }>
<UserProfile />
</set>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<get/{ username, email, updateUsername } = "App"/>
<div>
<h2>My Profile</h2>
<p>Username: ${username}</p>
<p>Email: ${email}</p>
<button onClick() { updateUsername("Jane") }>
Update username to Jane
</button>
</div>
3 changes: 3 additions & 0 deletions content/6-form-input/1-input-text/marko/InputHello.marko
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<let/text = "Hello world"/>
<p>${text}</p>
<input value:=text/>
Loading

0 comments on commit a01e903

Please sign in to comment.