create-fluxstack 1.20.1 → 1.21.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/LLMD/resources/live-components.md +103 -57
- package/LLMD/resources/live-rooms.md +187 -88
- package/README.md +27 -25
- package/app/client/.live-stubs/LiveCounter.js +4 -4
- package/app/client/src/App.tsx +11 -12
- package/app/client/src/components/AppLayout.tsx +290 -252
- package/app/client/src/components/BackButton.tsx +16 -13
- package/app/client/src/components/DemoPage.tsx +135 -22
- package/app/client/src/index.css +21 -11
- package/app/client/src/live/AuthDemo.tsx +270 -333
- package/app/client/src/live/CounterDemo.tsx +151 -206
- package/app/client/src/live/FormDemo.tsx +140 -119
- package/app/client/src/live/PingPongDemo.tsx +180 -202
- package/app/client/src/live/RoomChatDemo.tsx +397 -374
- package/app/client/src/pages/HomePage.tsx +170 -104
- package/app/server/live/LiveCounter.ts +71 -68
- package/app/server/live/LiveSharedCounter.ts +18 -12
- package/app/server/live/auto-generated-components.ts +1 -3
- package/app/server/live/rooms/CounterRoom.ts +15 -10
- package/core/client/index.ts +0 -3
- package/core/client/state/createStore.ts +88 -88
- package/core/client/state/index.ts +5 -5
- package/core/server/live/auto-generated-components.ts +1 -3
- package/core/utils/version.ts +1 -1
- package/package.json +1 -1
- package/tsconfig.json +7 -6
- package/app/client/src/components/LiveUploadWidget.tsx +0 -200
- package/app/client/src/live/UploadDemo.tsx +0 -21
- package/app/server/live/LiveUpload.ts +0 -96
- package/core/client/hooks/useLiveUpload.ts +0 -70
|
@@ -1,22 +1,135 @@
|
|
|
1
|
-
import type { ReactNode } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import type { ReactNode } from 'react'
|
|
2
|
+
import { Link, useLocation } from 'react-router'
|
|
3
|
+
import { FaArrowLeft, FaBolt } from 'react-icons/fa'
|
|
4
|
+
|
|
5
|
+
const demoNav = [
|
|
6
|
+
{ to: '/counter', label: 'Counter' },
|
|
7
|
+
{ to: '/form', label: 'Form' },
|
|
8
|
+
|
|
9
|
+
{ to: '/room-chat', label: 'Room Chat' },
|
|
10
|
+
{ to: '/auth', label: 'Auth' },
|
|
11
|
+
{ to: '/ping-pong', label: 'Ping Pong' },
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
const demoMeta: Record<string, { title: string; description: string; note?: ReactNode }> = {
|
|
15
|
+
'/counter': {
|
|
16
|
+
title: 'Counters',
|
|
17
|
+
description: 'Compare estado local, estado isolado por sala e estado compartilhado em tempo real.',
|
|
18
|
+
},
|
|
19
|
+
'/form': {
|
|
20
|
+
title: 'Live Form',
|
|
21
|
+
description: 'Formulario com campos sincronizados pelo servidor, debounce e estado compartilhado pelo proxy Live.',
|
|
22
|
+
note: <>Este formulario usa <code className="text-theme">Live.use()</code> - cada campo sincroniza automaticamente com o servidor.</>,
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
'/shared-counter': {
|
|
26
|
+
title: 'Shared Counter',
|
|
27
|
+
description: 'Uma sala global sincroniza usuarios, eventos e estado entre abas abertas ao mesmo tempo.',
|
|
28
|
+
note: <>Contador compartilhado usando <code className="text-theme">LiveRoom</code> - abra em varias abas.</>,
|
|
29
|
+
},
|
|
30
|
+
'/room-chat': {
|
|
31
|
+
title: 'Room Chat',
|
|
32
|
+
description: 'Chat multi-sala com salas publicas, salas protegidas por senha e mensagens em tempo real.',
|
|
33
|
+
note: <>Chat com multiplas salas usando o sistema <code className="text-theme">$room</code>.</>,
|
|
34
|
+
},
|
|
35
|
+
'/auth': {
|
|
36
|
+
title: 'Live Auth',
|
|
37
|
+
description: 'Fluxo de autenticacao para Live Components com roles, permissoes e painel protegido.',
|
|
38
|
+
note: <>Sistema de autenticacao declarativo para Live Components com <code className="text-theme">$auth</code>.</>,
|
|
39
|
+
},
|
|
40
|
+
'/ping-pong': {
|
|
41
|
+
title: 'Ping Pong Binary',
|
|
42
|
+
description: 'Mede round-trip time de mensagens binarias no WebSocket usando codec msgpack.',
|
|
43
|
+
note: <>Latency demo com <code className="text-theme-secondary">msgpack</code> binary codec - mensagens binarias no WebSocket.</>,
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface DemoPageProps {
|
|
48
|
+
children: ReactNode
|
|
49
|
+
title?: string
|
|
50
|
+
description?: string
|
|
51
|
+
eyebrow?: string
|
|
52
|
+
note?: ReactNode
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function DemoPage({
|
|
56
|
+
children,
|
|
57
|
+
title,
|
|
58
|
+
description,
|
|
59
|
+
eyebrow = 'Live Demo',
|
|
60
|
+
note,
|
|
61
|
+
}: DemoPageProps) {
|
|
62
|
+
const location = useLocation()
|
|
63
|
+
const meta = demoMeta[location.pathname]
|
|
64
|
+
const pageTitle = title ?? meta?.title ?? 'Live Component Demo'
|
|
65
|
+
const pageDescription = description ?? meta?.description ?? 'Explore uma capacidade do runtime Live em uma interface conectada ao servidor.'
|
|
66
|
+
const pageNote = meta?.note ?? note
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<div className="relative min-h-[calc(100vh-128px)] overflow-hidden px-4 py-8 sm:px-6 lg:px-8">
|
|
70
|
+
<div className="absolute inset-0 app-grid-bg opacity-45" />
|
|
71
|
+
|
|
72
|
+
<div className="relative z-10 mx-auto flex w-full max-w-7xl flex-col gap-6">
|
|
73
|
+
<div className="flex flex-col gap-4">
|
|
74
|
+
<Link
|
|
75
|
+
to="/"
|
|
76
|
+
className="inline-flex w-fit items-center gap-2 rounded-lg border border-white/10 bg-white/[0.03] px-3 py-2 text-sm text-gray-300 transition hover:border-white/20 hover:bg-white/[0.06] hover:text-white"
|
|
77
|
+
>
|
|
78
|
+
<FaArrowLeft className="h-3 w-3" />
|
|
79
|
+
Home
|
|
80
|
+
</Link>
|
|
81
|
+
|
|
82
|
+
<section className="rounded-lg border border-white/10 bg-[#07070b]/75 p-5 shadow-2xl shadow-black/20 backdrop-blur sm:p-6">
|
|
83
|
+
<div className="flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
|
|
84
|
+
<div className="max-w-3xl">
|
|
85
|
+
<div className="mb-4 inline-flex items-center gap-2 rounded-full border border-theme-active bg-theme-muted px-3 py-1 text-xs font-medium text-theme">
|
|
86
|
+
<FaBolt className="h-3 w-3" />
|
|
87
|
+
{eyebrow}
|
|
88
|
+
</div>
|
|
89
|
+
<h1 className="text-3xl font-semibold tracking-tight text-white sm:text-4xl">
|
|
90
|
+
{pageTitle}
|
|
91
|
+
</h1>
|
|
92
|
+
<p className="mt-3 max-w-2xl text-sm leading-7 text-gray-400 sm:text-base">
|
|
93
|
+
{pageDescription}
|
|
94
|
+
</p>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<div className="flex flex-wrap gap-2 lg:justify-end">
|
|
98
|
+
{demoNav.map(item => {
|
|
99
|
+
const active = location.pathname === item.to
|
|
100
|
+
return (
|
|
101
|
+
<Link
|
|
102
|
+
key={item.to}
|
|
103
|
+
to={item.to}
|
|
104
|
+
className={`rounded-lg border px-3 py-2 text-xs font-medium transition ${
|
|
105
|
+
active
|
|
106
|
+
? 'border-white bg-white text-black'
|
|
107
|
+
: 'border-white/10 bg-white/[0.025] text-gray-400 hover:border-white/20 hover:bg-white/[0.06] hover:text-white'
|
|
108
|
+
}`}
|
|
109
|
+
>
|
|
110
|
+
{item.label}
|
|
111
|
+
</Link>
|
|
112
|
+
)
|
|
113
|
+
})}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</section>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<section className="rounded-lg border border-white/10 bg-black/20 p-3 shadow-2xl shadow-black/20 backdrop-blur sm:p-5">
|
|
120
|
+
<div className="mx-auto flex w-full max-w-6xl flex-col items-center">
|
|
121
|
+
{children}
|
|
122
|
+
</div>
|
|
123
|
+
</section>
|
|
124
|
+
|
|
125
|
+
{pageNote && (
|
|
126
|
+
<aside className="mx-auto w-full max-w-3xl rounded-lg border border-theme bg-theme-accent px-4 py-3 text-center">
|
|
127
|
+
<p className="text-xs leading-6 text-gray-400 sm:text-sm">
|
|
128
|
+
{pageNote}
|
|
129
|
+
</p>
|
|
130
|
+
</aside>
|
|
131
|
+
)}
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
)
|
|
135
|
+
}
|
package/app/client/src/index.css
CHANGED
|
@@ -35,10 +35,19 @@
|
|
|
35
35
|
.shadow-theme { box-shadow: 0 4px 14px var(--theme-primary-glow); }
|
|
36
36
|
.glow-theme { filter: drop-shadow(0 0 12px var(--theme-primary-glow)); }
|
|
37
37
|
|
|
38
|
-
.bg-theme-gradient {
|
|
39
|
-
background-image: var(--theme-gradient-primary,
|
|
40
|
-
linear-gradient(to right, var(--theme-primary), var(--theme-secondary)));
|
|
41
|
-
}
|
|
38
|
+
.bg-theme-gradient {
|
|
39
|
+
background-image: var(--theme-gradient-primary,
|
|
40
|
+
linear-gradient(to right, var(--theme-primary), var(--theme-secondary)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.app-grid-bg {
|
|
44
|
+
background-image:
|
|
45
|
+
linear-gradient(rgba(255, 255, 255, 0.055) 1px, transparent 1px),
|
|
46
|
+
linear-gradient(90deg, rgba(255, 255, 255, 0.055) 1px, transparent 1px),
|
|
47
|
+
radial-gradient(circle at 50% 0%, var(--theme-bg-accent), transparent 42%);
|
|
48
|
+
background-size: 48px 48px, 48px 48px, 100% 100%;
|
|
49
|
+
mask-image: linear-gradient(to bottom, black 0%, black 72%, transparent 100%);
|
|
50
|
+
}
|
|
42
51
|
|
|
43
52
|
/* Hover variants */
|
|
44
53
|
.hover\:bg-theme-muted:hover { background-color: var(--theme-primary-muted); }
|
|
@@ -198,13 +207,14 @@
|
|
|
198
207
|
box-sizing: border-box;
|
|
199
208
|
}
|
|
200
209
|
|
|
201
|
-
body {
|
|
202
|
-
margin: 0;
|
|
203
|
-
padding: 0;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
-
|
|
207
|
-
|
|
210
|
+
body {
|
|
211
|
+
margin: 0;
|
|
212
|
+
padding: 0;
|
|
213
|
+
background: #050508;
|
|
214
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
215
|
+
-webkit-font-smoothing: antialiased;
|
|
216
|
+
-moz-osx-font-smoothing: grayscale;
|
|
217
|
+
}
|
|
208
218
|
|
|
209
219
|
html {
|
|
210
220
|
scroll-behavior: smooth;
|