@zessjs/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/index.ts +210 -0
- package/package.json +37 -0
- package/template/common/README.md +61 -0
- package/template/common/package.json +33 -0
- package/template/common/public/zess.svg +1 -0
- package/template/common/src/assets/style.css +30 -0
- package/template/common/src/assets/vite.svg +1 -0
- package/template/javascript/eslint.config.js +10 -0
- package/template/javascript/index.html +13 -0
- package/template/javascript/jsconfig.json +11 -0
- package/template/javascript/src/App.jsx +101 -0
- package/template/javascript/src/pages/ConditionalPage.jsx +85 -0
- package/template/javascript/src/pages/CounterPage.jsx +50 -0
- package/template/javascript/src/pages/HomePage.jsx +43 -0
- package/template/javascript/src/pages/ListPage.jsx +83 -0
- package/template/javascript/tests/HelloWorld.test.jsx +15 -0
- package/template/javascript/vite.config.js +11 -0
- package/template/typescript/eslint.config.ts +2 -0
- package/template/typescript/index.html +13 -0
- package/template/typescript/src/App.tsx +101 -0
- package/template/typescript/src/pages/ConditionalPage.tsx +92 -0
- package/template/typescript/src/pages/CounterPage.tsx +50 -0
- package/template/typescript/src/pages/HomePage.tsx +44 -0
- package/template/typescript/src/pages/ListPage.tsx +83 -0
- package/template/typescript/tests/HelloWorld.test.tsx +15 -0
- package/template/typescript/tsconfig.json +22 -0
- package/template/typescript/vite.config.ts +12 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Match, Show, Switch, useMemo, useSignal } from '@zessjs/core'
|
|
2
|
+
import { Link } from '@zessjs/router'
|
|
3
|
+
|
|
4
|
+
const ConditionalPage = () => {
|
|
5
|
+
const [count, setCount] = useSignal(0)
|
|
6
|
+
const status = useMemo(() => {
|
|
7
|
+
const currentCount = count()
|
|
8
|
+
if (currentCount > 10) return 'success'
|
|
9
|
+
if (currentCount > 5) return 'warning'
|
|
10
|
+
return 'info'
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<div class="w-full text-center pb-8">
|
|
15
|
+
<header class="mb-8">
|
|
16
|
+
<h1 class="text-2xl font-bold mb-2">Conditional Rendering</h1>
|
|
17
|
+
<p class="text-gray-600">
|
|
18
|
+
This demonstrates Zess's conditional rendering components
|
|
19
|
+
</p>
|
|
20
|
+
</header>
|
|
21
|
+
<div class="flex justify-center items-center gap-4 mb-8">
|
|
22
|
+
<button
|
|
23
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
24
|
+
onClick={() => setCount((prevCount) => Math.max(0, prevCount - 1))}
|
|
25
|
+
>
|
|
26
|
+
-
|
|
27
|
+
</button>
|
|
28
|
+
<span class="text-3xl font-bold min-w-16">{count()}</span>
|
|
29
|
+
<button
|
|
30
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
31
|
+
onClick={() => setCount((prevCount) => prevCount + 1)}
|
|
32
|
+
>
|
|
33
|
+
+
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="mb-8 space-y-4 max-w-md mx-auto">
|
|
37
|
+
<div class="p-4 border border-gray-200 rounded bg-white">
|
|
38
|
+
<h3 class="text-lg font-semibold mb-2">Using Show Component</h3>
|
|
39
|
+
{/* Show component renders content conditionally based on the 'when' prop */}
|
|
40
|
+
{/* Falls back to the fallback content when condition is false */}
|
|
41
|
+
<Show
|
|
42
|
+
when={count() > 5}
|
|
43
|
+
fallback={
|
|
44
|
+
<p class="text-gray-600">Count is less than or equal to 5</p>
|
|
45
|
+
}
|
|
46
|
+
>
|
|
47
|
+
<p class="text-green-600 font-medium">
|
|
48
|
+
Count is greater than 5! 🎉
|
|
49
|
+
</p>
|
|
50
|
+
</Show>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="p-4 border border-gray-200 rounded bg-white">
|
|
53
|
+
<h3 class="text-lg font-semibold mb-2">
|
|
54
|
+
Using {'<Switch>'} and {'<Match>'}
|
|
55
|
+
</h3>
|
|
56
|
+
{/* Switch component acts like a switch statement for rendering */}
|
|
57
|
+
{/* Only the first matching Match component within Switch is rendered */}
|
|
58
|
+
<Switch>
|
|
59
|
+
<Match when={status() === 'success'}>
|
|
60
|
+
<p class="text-green-600 font-medium">Status: Success</p>
|
|
61
|
+
</Match>
|
|
62
|
+
<Match when={status() === 'warning'}>
|
|
63
|
+
<p class="text-yellow-600 font-medium">Status: Warning</p>
|
|
64
|
+
</Match>
|
|
65
|
+
<Match when={status() === 'info'}>
|
|
66
|
+
<p class="text-blue-600 font-medium">Status: Info</p>
|
|
67
|
+
</Match>
|
|
68
|
+
</Switch>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<div>
|
|
72
|
+
{/* Link back to home page */}
|
|
73
|
+
<Link
|
|
74
|
+
to="/"
|
|
75
|
+
relative={false}
|
|
76
|
+
class="inline-block px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
77
|
+
>
|
|
78
|
+
Back to Home
|
|
79
|
+
</Link>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export default ConditionalPage
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useMemo, useSignal } from '@zessjs/core'
|
|
2
|
+
import { Link } from '@zessjs/router'
|
|
3
|
+
|
|
4
|
+
const CounterPage = () => {
|
|
5
|
+
const [count, setCount] = useSignal(0)
|
|
6
|
+
const doubleCount = useMemo(() => count() * 2)
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div class="w-full text-center pb-8">
|
|
10
|
+
<header class="mb-8">
|
|
11
|
+
<h1 class="text-2xl font-bold mb-2">Counter Example</h1>
|
|
12
|
+
<p class="text-gray-600">
|
|
13
|
+
This is a simple counter demonstrating Zess's signal system
|
|
14
|
+
</p>
|
|
15
|
+
</header>
|
|
16
|
+
<div class="flex justify-center items-center gap-4 mb-8">
|
|
17
|
+
<button
|
|
18
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
19
|
+
onClick={() => setCount((prevCount) => prevCount - 1)}
|
|
20
|
+
>
|
|
21
|
+
-
|
|
22
|
+
</button>
|
|
23
|
+
<span class="text-3xl font-bold min-w-16">{count()}</span>
|
|
24
|
+
<button
|
|
25
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
26
|
+
onClick={() => setCount((prevCount) => prevCount + 1)}
|
|
27
|
+
>
|
|
28
|
+
+
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="mb-8">
|
|
32
|
+
<p class="text-gray-700">
|
|
33
|
+
Double the count is: <strong>{doubleCount()}</strong>
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
{/* Link back to home page */}
|
|
38
|
+
<Link
|
|
39
|
+
to="/"
|
|
40
|
+
relative={false}
|
|
41
|
+
class="inline-block px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
42
|
+
>
|
|
43
|
+
Back to Home
|
|
44
|
+
</Link>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default CounterPage
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Link } from '@zessjs/router'
|
|
2
|
+
|
|
3
|
+
const HomePage = () => (
|
|
4
|
+
<div class="w-full text-center pb-8">
|
|
5
|
+
<section>
|
|
6
|
+
<h2 class="text-2xl font-semibold mb-6">Explore Examples</h2>
|
|
7
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
8
|
+
{/* Counter example card - links to counter page */}
|
|
9
|
+
<Link
|
|
10
|
+
to="counter"
|
|
11
|
+
class="block p-4 border border-gray-200 rounded hover:border-indigo-500 transition-all bg-white"
|
|
12
|
+
>
|
|
13
|
+
<h3 class="text-lg font-medium mb-2">Counter Example</h3>
|
|
14
|
+
<p class="text-sm text-gray-600">
|
|
15
|
+
Signal system and reactive updates
|
|
16
|
+
</p>
|
|
17
|
+
</Link>
|
|
18
|
+
{/* List example card - links to list page */}
|
|
19
|
+
<Link
|
|
20
|
+
to="list"
|
|
21
|
+
class="block p-4 border border-gray-200 rounded hover:border-purple-500 transition-all bg-white"
|
|
22
|
+
>
|
|
23
|
+
<h3 class="text-lg font-medium mb-2">List Example</h3>
|
|
24
|
+
<p class="text-sm text-gray-600">
|
|
25
|
+
Render lists and handle user input
|
|
26
|
+
</p>
|
|
27
|
+
</Link>
|
|
28
|
+
{/* Conditional rendering example card - links to conditional page */}
|
|
29
|
+
<Link
|
|
30
|
+
to="conditional"
|
|
31
|
+
class="block p-4 border border-gray-200 rounded hover:border-pink-500 transition-all bg-white"
|
|
32
|
+
>
|
|
33
|
+
<h3 class="text-lg font-medium mb-2">Conditional Rendering</h3>
|
|
34
|
+
<p class="text-sm text-gray-600">
|
|
35
|
+
{'<Show>'} and {'<Switch>'} components
|
|
36
|
+
</p>
|
|
37
|
+
</Link>
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
40
|
+
</div>
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
export default HomePage
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { For, Show, useSignal } from '@zessjs/core'
|
|
2
|
+
import { Link } from '@zessjs/router'
|
|
3
|
+
|
|
4
|
+
const ListPage = () => {
|
|
5
|
+
const [items, setItems] = useSignal([
|
|
6
|
+
'Zess Compiler',
|
|
7
|
+
'Zess Core',
|
|
8
|
+
'Zess Router',
|
|
9
|
+
])
|
|
10
|
+
const [newItem, setNewItem] = useSignal('')
|
|
11
|
+
const addItem = () => {
|
|
12
|
+
const item = newItem().trim()
|
|
13
|
+
if (item) {
|
|
14
|
+
setItems((prevItems) => [...prevItems, item])
|
|
15
|
+
setNewItem('')
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const handleKeyPress = (e) => {
|
|
19
|
+
if (e.key === 'Enter') addItem()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div class="w-full text-center pb-8">
|
|
24
|
+
<header class="mb-8">
|
|
25
|
+
<h1 class="text-2xl font-bold mb-2">List Example</h1>
|
|
26
|
+
<p class="text-gray-600">
|
|
27
|
+
This shows how to render lists with {'<For>'} component
|
|
28
|
+
</p>
|
|
29
|
+
</header>
|
|
30
|
+
<div class="mb-8">
|
|
31
|
+
<div class="flex flex-col sm:flex-row gap-2 justify-center">
|
|
32
|
+
<input
|
|
33
|
+
type="text"
|
|
34
|
+
value={newItem()}
|
|
35
|
+
onInput={(e) => setNewItem(e.target.value)}
|
|
36
|
+
onKeyPress={handleKeyPress}
|
|
37
|
+
placeholder="Enter new item..."
|
|
38
|
+
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-indigo-500"
|
|
39
|
+
/>
|
|
40
|
+
<button
|
|
41
|
+
onClick={addItem}
|
|
42
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
43
|
+
>
|
|
44
|
+
Add Item
|
|
45
|
+
</button>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="mb-8">
|
|
49
|
+
{/* Conditionally render the list or an empty state message */}
|
|
50
|
+
<Show
|
|
51
|
+
when={items().length > 0}
|
|
52
|
+
fallback={<p class="text-gray-500 py-4">No items in the list yet.</p>}
|
|
53
|
+
>
|
|
54
|
+
<ul class="space-y-2 max-w-md mx-auto">
|
|
55
|
+
{/* Zess For component for efficiently rendering lists */}
|
|
56
|
+
<For each={items()}>
|
|
57
|
+
{(item, index) => (
|
|
58
|
+
<li class="flex items-center p-2 border-b border-gray-200 bg-white">
|
|
59
|
+
<span class="mr-2 text-gray-500 font-medium">
|
|
60
|
+
{index() + 1}.
|
|
61
|
+
</span>
|
|
62
|
+
<span class="text-left flex-1">{item}</span>
|
|
63
|
+
</li>
|
|
64
|
+
)}
|
|
65
|
+
</For>
|
|
66
|
+
</ul>
|
|
67
|
+
</Show>
|
|
68
|
+
</div>
|
|
69
|
+
<div>
|
|
70
|
+
{/* Link back to home page */}
|
|
71
|
+
<Link
|
|
72
|
+
to="/"
|
|
73
|
+
relative={false}
|
|
74
|
+
class="inline-block px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
75
|
+
>
|
|
76
|
+
Back to Home
|
|
77
|
+
</Link>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default ListPage
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { render } from '@zessjs/core'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
function HelloWorld() {
|
|
5
|
+
return <div>Hello World</div>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
describe('HelloWorld', () => {
|
|
9
|
+
it('should render a <HelloWorld> component', () => {
|
|
10
|
+
const container = document.createElement('div')
|
|
11
|
+
const dispose = render(() => <HelloWorld />, container)
|
|
12
|
+
expect(container.textContent).toBe('Hello World')
|
|
13
|
+
dispose()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
2
|
+
import zess from '@zessjs/vite-plugin'
|
|
3
|
+
import { defineConfig } from 'vite'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [tailwindcss(), zess()],
|
|
7
|
+
test: {
|
|
8
|
+
environment: 'jsdom',
|
|
9
|
+
include: ['./tests/*.test.{js,jsx}'],
|
|
10
|
+
},
|
|
11
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/zess.svg" />
|
|
7
|
+
<title>Zess App</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/App.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { render, type Component } from '@zessjs/core'
|
|
2
|
+
import { Link, Route, Router } from '@zessjs/router'
|
|
3
|
+
import viteLogo from './assets/vite.svg'
|
|
4
|
+
import ConditionalPage from './pages/ConditionalPage'
|
|
5
|
+
import CounterPage from './pages/CounterPage'
|
|
6
|
+
import HomePage from './pages/HomePage'
|
|
7
|
+
import ListPage from './pages/ListPage'
|
|
8
|
+
import './assets/style.css'
|
|
9
|
+
import zessLogo from '/zess.svg'
|
|
10
|
+
|
|
11
|
+
const AppLayout: Component<{ children?: JSX.Element }> = (props) => (
|
|
12
|
+
<div class="min-h-screen flex flex-col items-center bg-gradient-to-br from-blue-100 via-white to-yellow-100">
|
|
13
|
+
<nav class="w-full py-4 flex justify-center">
|
|
14
|
+
<div class="flex space-x-6 md:space-x-8">
|
|
15
|
+
{/* Home page link - active when at root URL */}
|
|
16
|
+
<Link
|
|
17
|
+
end
|
|
18
|
+
to="/"
|
|
19
|
+
class="text-gray-700 hover:text-indigo-600 transition-all duration-200"
|
|
20
|
+
activeClass="text-indigo-600 font-semibold"
|
|
21
|
+
>
|
|
22
|
+
Home
|
|
23
|
+
</Link>
|
|
24
|
+
{/* Counter page link */}
|
|
25
|
+
<Link
|
|
26
|
+
end
|
|
27
|
+
to="counter"
|
|
28
|
+
class="text-gray-700 hover:text-indigo-600 transition-all duration-200"
|
|
29
|
+
activeClass="text-indigo-600 font-semibold"
|
|
30
|
+
>
|
|
31
|
+
Counter
|
|
32
|
+
</Link>
|
|
33
|
+
{/* List page link */}
|
|
34
|
+
<Link
|
|
35
|
+
end
|
|
36
|
+
to="list"
|
|
37
|
+
class="text-gray-700 hover:text-indigo-600 transition-all duration-200"
|
|
38
|
+
activeClass="text-indigo-600 font-semibold"
|
|
39
|
+
>
|
|
40
|
+
List
|
|
41
|
+
</Link>
|
|
42
|
+
{/* Conditional page link */}
|
|
43
|
+
<Link
|
|
44
|
+
end
|
|
45
|
+
to="conditional"
|
|
46
|
+
class="text-gray-700 hover:text-indigo-600 transition-all duration-200"
|
|
47
|
+
activeClass="text-indigo-600 font-semibold"
|
|
48
|
+
>
|
|
49
|
+
Conditional
|
|
50
|
+
</Link>
|
|
51
|
+
</div>
|
|
52
|
+
</nav>
|
|
53
|
+
<div class="flex flex-col md:flex-row items-center justify-center my-8 md:my-12 space-y-4 md:space-y-0 md:space-x-12">
|
|
54
|
+
<img
|
|
55
|
+
src={zessLogo}
|
|
56
|
+
class="h-32 md:h-40 transition-all duration-300 hover:drop-shadow-[0_0_2em_#646cffaa]"
|
|
57
|
+
alt="Zess logo"
|
|
58
|
+
/>
|
|
59
|
+
<img
|
|
60
|
+
src={viteLogo}
|
|
61
|
+
class="h-32 md:h-40 transition-all duration-300 hover:drop-shadow-[0_0_2em_#646cffaa]"
|
|
62
|
+
alt="Vite logo"
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
<h1 class="text-5xl md:text-6xl font-bold mb-8 md:mb-12">Hello Zess!</h1>
|
|
66
|
+
<main class="w-full max-w-4xl px-4 pb-12">{props.children}</main>
|
|
67
|
+
</div>
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const ZessApp: Component = () => (
|
|
71
|
+
<Router root={AppLayout} mode="history">
|
|
72
|
+
{/* Route for Home page */}
|
|
73
|
+
<Route path="/" component={HomePage} />
|
|
74
|
+
{/* Route for Counter page */}
|
|
75
|
+
<Route path="counter" component={CounterPage} />
|
|
76
|
+
{/* Route for List page */}
|
|
77
|
+
<Route path="list" component={ListPage} />
|
|
78
|
+
{/* Route for Conditional page */}
|
|
79
|
+
<Route path="conditional" component={ConditionalPage} />
|
|
80
|
+
{/* Catch-all route for 404 page not found */}
|
|
81
|
+
<Route
|
|
82
|
+
path="*"
|
|
83
|
+
component={() => (
|
|
84
|
+
<div class="text-center py-16">
|
|
85
|
+
<h1 class="text-4xl font-bold mb-4">404</h1>
|
|
86
|
+
<p class="text-xl text-gray-600 mb-8">Page not found</p>
|
|
87
|
+
{/* Link to home page */}
|
|
88
|
+
<Link
|
|
89
|
+
to="/"
|
|
90
|
+
relative={false}
|
|
91
|
+
class="inline-block px-6 py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded transition-all"
|
|
92
|
+
>
|
|
93
|
+
Go back to Home
|
|
94
|
+
</Link>
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
/>
|
|
98
|
+
</Router>
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
render(() => <ZessApp />, document.querySelector('#app')!)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Match,
|
|
3
|
+
Show,
|
|
4
|
+
Switch,
|
|
5
|
+
useMemo,
|
|
6
|
+
useSignal,
|
|
7
|
+
type Component,
|
|
8
|
+
} from '@zessjs/core'
|
|
9
|
+
import { Link } from '@zessjs/router'
|
|
10
|
+
|
|
11
|
+
const ConditionalPage: Component = () => {
|
|
12
|
+
const [count, setCount] = useSignal(0)
|
|
13
|
+
const status = useMemo(() => {
|
|
14
|
+
const currentCount = count()
|
|
15
|
+
if (currentCount > 10) return 'success'
|
|
16
|
+
if (currentCount > 5) return 'warning'
|
|
17
|
+
return 'info'
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div class="w-full text-center pb-8">
|
|
22
|
+
<header class="mb-8">
|
|
23
|
+
<h1 class="text-2xl font-bold mb-2">Conditional Rendering</h1>
|
|
24
|
+
<p class="text-gray-600">
|
|
25
|
+
This demonstrates Zess's conditional rendering components
|
|
26
|
+
</p>
|
|
27
|
+
</header>
|
|
28
|
+
<div class="flex justify-center items-center gap-4 mb-8">
|
|
29
|
+
<button
|
|
30
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
31
|
+
onClick={() => setCount((prevCount) => Math.max(0, prevCount - 1))}
|
|
32
|
+
>
|
|
33
|
+
-
|
|
34
|
+
</button>
|
|
35
|
+
<span class="text-3xl font-bold min-w-16">{count()}</span>
|
|
36
|
+
<button
|
|
37
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
38
|
+
onClick={() => setCount((prevCount) => prevCount + 1)}
|
|
39
|
+
>
|
|
40
|
+
+
|
|
41
|
+
</button>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="mb-8 space-y-4 max-w-md mx-auto">
|
|
44
|
+
<div class="p-4 border border-gray-200 rounded bg-white">
|
|
45
|
+
<h3 class="text-lg font-semibold mb-2">Using Show Component</h3>
|
|
46
|
+
{/* Show component renders content conditionally based on the 'when' prop */}
|
|
47
|
+
{/* Falls back to the fallback content when condition is false */}
|
|
48
|
+
<Show
|
|
49
|
+
when={count() > 5}
|
|
50
|
+
fallback={
|
|
51
|
+
<p class="text-gray-600">Count is less than or equal to 5</p>
|
|
52
|
+
}
|
|
53
|
+
>
|
|
54
|
+
<p class="text-green-600 font-medium">
|
|
55
|
+
Count is greater than 5! 🎉
|
|
56
|
+
</p>
|
|
57
|
+
</Show>
|
|
58
|
+
</div>
|
|
59
|
+
<div class="p-4 border border-gray-200 rounded bg-white">
|
|
60
|
+
<h3 class="text-lg font-semibold mb-2">
|
|
61
|
+
Using {'<Switch>'} and {'<Match>'}
|
|
62
|
+
</h3>
|
|
63
|
+
{/* Switch component acts like a switch statement for rendering */}
|
|
64
|
+
{/* Only the first matching Match component within Switch is rendered */}
|
|
65
|
+
<Switch>
|
|
66
|
+
<Match when={status() === 'success'}>
|
|
67
|
+
<p class="text-green-600 font-medium">Status: Success</p>
|
|
68
|
+
</Match>
|
|
69
|
+
<Match when={status() === 'warning'}>
|
|
70
|
+
<p class="text-yellow-600 font-medium">Status: Warning</p>
|
|
71
|
+
</Match>
|
|
72
|
+
<Match when={status() === 'info'}>
|
|
73
|
+
<p class="text-blue-600 font-medium">Status: Info</p>
|
|
74
|
+
</Match>
|
|
75
|
+
</Switch>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
<div>
|
|
79
|
+
{/* Link back to home page */}
|
|
80
|
+
<Link
|
|
81
|
+
to="/"
|
|
82
|
+
relative={false}
|
|
83
|
+
class="inline-block px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
84
|
+
>
|
|
85
|
+
Back to Home
|
|
86
|
+
</Link>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export default ConditionalPage
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useMemo, useSignal, type Component } from '@zessjs/core'
|
|
2
|
+
import { Link } from '@zessjs/router'
|
|
3
|
+
|
|
4
|
+
const CounterPage: Component = () => {
|
|
5
|
+
const [count, setCount] = useSignal(0)
|
|
6
|
+
const doubleCount = useMemo(() => count() * 2)
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div class="w-full text-center pb-8">
|
|
10
|
+
<header class="mb-8">
|
|
11
|
+
<h1 class="text-2xl font-bold mb-2">Counter Example</h1>
|
|
12
|
+
<p class="text-gray-600">
|
|
13
|
+
This is a simple counter demonstrating Zess's signal system
|
|
14
|
+
</p>
|
|
15
|
+
</header>
|
|
16
|
+
<div class="flex justify-center items-center gap-4 mb-8">
|
|
17
|
+
<button
|
|
18
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
19
|
+
onClick={() => setCount((prevCount) => prevCount - 1)}
|
|
20
|
+
>
|
|
21
|
+
-
|
|
22
|
+
</button>
|
|
23
|
+
<span class="text-3xl font-bold min-w-16">{count()}</span>
|
|
24
|
+
<button
|
|
25
|
+
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
26
|
+
onClick={() => setCount((prevCount) => prevCount + 1)}
|
|
27
|
+
>
|
|
28
|
+
+
|
|
29
|
+
</button>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="mb-8">
|
|
32
|
+
<p class="text-gray-700">
|
|
33
|
+
Double the count is: <strong>{doubleCount()}</strong>
|
|
34
|
+
</p>
|
|
35
|
+
</div>
|
|
36
|
+
<div>
|
|
37
|
+
{/* Link back to home page */}
|
|
38
|
+
<Link
|
|
39
|
+
to="/"
|
|
40
|
+
relative={false}
|
|
41
|
+
class="inline-block px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded transition-all"
|
|
42
|
+
>
|
|
43
|
+
Back to Home
|
|
44
|
+
</Link>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default CounterPage
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Link } from '@zessjs/router'
|
|
2
|
+
import type { Component } from '@zessjs/core'
|
|
3
|
+
|
|
4
|
+
const HomePage: Component = () => (
|
|
5
|
+
<div class="w-full text-center pb-8">
|
|
6
|
+
<section>
|
|
7
|
+
<h2 class="text-2xl font-semibold mb-6">Explore Examples</h2>
|
|
8
|
+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
9
|
+
{/* Counter example card - links to counter page */}
|
|
10
|
+
<Link
|
|
11
|
+
to="counter"
|
|
12
|
+
class="block p-4 border border-gray-200 rounded hover:border-indigo-500 transition-all bg-white"
|
|
13
|
+
>
|
|
14
|
+
<h3 class="text-lg font-medium mb-2">Counter Example</h3>
|
|
15
|
+
<p class="text-sm text-gray-600">
|
|
16
|
+
Signal system and reactive updates
|
|
17
|
+
</p>
|
|
18
|
+
</Link>
|
|
19
|
+
{/* List example card - links to list page */}
|
|
20
|
+
<Link
|
|
21
|
+
to="list"
|
|
22
|
+
class="block p-4 border border-gray-200 rounded hover:border-purple-500 transition-all bg-white"
|
|
23
|
+
>
|
|
24
|
+
<h3 class="text-lg font-medium mb-2">List Example</h3>
|
|
25
|
+
<p class="text-sm text-gray-600">
|
|
26
|
+
Render lists and handle user input
|
|
27
|
+
</p>
|
|
28
|
+
</Link>
|
|
29
|
+
{/* Conditional rendering example card - links to conditional page */}
|
|
30
|
+
<Link
|
|
31
|
+
to="conditional"
|
|
32
|
+
class="block p-4 border border-gray-200 rounded hover:border-pink-500 transition-all bg-white"
|
|
33
|
+
>
|
|
34
|
+
<h3 class="text-lg font-medium mb-2">Conditional Rendering</h3>
|
|
35
|
+
<p class="text-sm text-gray-600">
|
|
36
|
+
{'<Show>'} and {'<Switch>'} components
|
|
37
|
+
</p>
|
|
38
|
+
</Link>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
41
|
+
</div>
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
export default HomePage
|