@jonsoc/web 1.1.49 → 1.1.51
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/package.json +4 -4
- package/src/routeTree.gen.ts +39 -3
- package/src/routes/__root.tsx +2 -0
- package/src/routes/landing.tsx +239 -0
- package/src/routes/share.$id.tsx +148 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jonsoc/web",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.51",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"@base-ui/react": "1.1.0",
|
|
18
18
|
"@convex-dev/better-auth": "0.10.10",
|
|
19
19
|
"@hookform/resolvers": "5.2.2",
|
|
20
|
-
"@jonsoc/convex": "1.1.
|
|
21
|
-
"@jonsoc/env": "1.1.
|
|
20
|
+
"@jonsoc/convex": "1.1.51",
|
|
21
|
+
"@jonsoc/env": "1.1.51",
|
|
22
22
|
"@tailwindcss/vite": "4.1.11",
|
|
23
23
|
"@tanstack/react-form": "1.28.0",
|
|
24
24
|
"@tanstack/react-router": "1.157.18",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"zod": "4.1.8"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@jonsoc/config": "1.1.
|
|
39
|
+
"@jonsoc/config": "1.1.51",
|
|
40
40
|
"@tanstack/react-router-devtools": "1.157.18",
|
|
41
41
|
"@tanstack/router-plugin": "1.157.18",
|
|
42
42
|
"@types/react": "19.2.7",
|
package/src/routeTree.gen.ts
CHANGED
|
@@ -9,9 +9,16 @@
|
|
|
9
9
|
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
10
10
|
|
|
11
11
|
import { Route as rootRouteImport } from './routes/__root'
|
|
12
|
+
import { Route as LandingRouteImport } from './routes/landing'
|
|
12
13
|
import { Route as DashboardRouteImport } from './routes/dashboard'
|
|
13
14
|
import { Route as IndexRouteImport } from './routes/index'
|
|
15
|
+
import { Route as ShareIdRouteImport } from './routes/share.$id'
|
|
14
16
|
|
|
17
|
+
const LandingRoute = LandingRouteImport.update({
|
|
18
|
+
id: '/landing',
|
|
19
|
+
path: '/landing',
|
|
20
|
+
getParentRoute: () => rootRouteImport,
|
|
21
|
+
} as any)
|
|
15
22
|
const DashboardRoute = DashboardRouteImport.update({
|
|
16
23
|
id: '/dashboard',
|
|
17
24
|
path: '/dashboard',
|
|
@@ -22,35 +29,55 @@ const IndexRoute = IndexRouteImport.update({
|
|
|
22
29
|
path: '/',
|
|
23
30
|
getParentRoute: () => rootRouteImport,
|
|
24
31
|
} as any)
|
|
32
|
+
const ShareIdRoute = ShareIdRouteImport.update({
|
|
33
|
+
id: '/share/$id',
|
|
34
|
+
path: '/share/$id',
|
|
35
|
+
getParentRoute: () => rootRouteImport,
|
|
36
|
+
} as any)
|
|
25
37
|
|
|
26
38
|
export interface FileRoutesByFullPath {
|
|
27
39
|
'/': typeof IndexRoute
|
|
28
40
|
'/dashboard': typeof DashboardRoute
|
|
41
|
+
'/landing': typeof LandingRoute
|
|
42
|
+
'/share/$id': typeof ShareIdRoute
|
|
29
43
|
}
|
|
30
44
|
export interface FileRoutesByTo {
|
|
31
45
|
'/': typeof IndexRoute
|
|
32
46
|
'/dashboard': typeof DashboardRoute
|
|
47
|
+
'/landing': typeof LandingRoute
|
|
48
|
+
'/share/$id': typeof ShareIdRoute
|
|
33
49
|
}
|
|
34
50
|
export interface FileRoutesById {
|
|
35
51
|
__root__: typeof rootRouteImport
|
|
36
52
|
'/': typeof IndexRoute
|
|
37
53
|
'/dashboard': typeof DashboardRoute
|
|
54
|
+
'/landing': typeof LandingRoute
|
|
55
|
+
'/share/$id': typeof ShareIdRoute
|
|
38
56
|
}
|
|
39
57
|
export interface FileRouteTypes {
|
|
40
58
|
fileRoutesByFullPath: FileRoutesByFullPath
|
|
41
|
-
fullPaths: '/' | '/dashboard'
|
|
59
|
+
fullPaths: '/' | '/dashboard' | '/landing' | '/share/$id'
|
|
42
60
|
fileRoutesByTo: FileRoutesByTo
|
|
43
|
-
to: '/' | '/dashboard'
|
|
44
|
-
id: '__root__' | '/' | '/dashboard'
|
|
61
|
+
to: '/' | '/dashboard' | '/landing' | '/share/$id'
|
|
62
|
+
id: '__root__' | '/' | '/dashboard' | '/landing' | '/share/$id'
|
|
45
63
|
fileRoutesById: FileRoutesById
|
|
46
64
|
}
|
|
47
65
|
export interface RootRouteChildren {
|
|
48
66
|
IndexRoute: typeof IndexRoute
|
|
49
67
|
DashboardRoute: typeof DashboardRoute
|
|
68
|
+
LandingRoute: typeof LandingRoute
|
|
69
|
+
ShareIdRoute: typeof ShareIdRoute
|
|
50
70
|
}
|
|
51
71
|
|
|
52
72
|
declare module '@tanstack/react-router' {
|
|
53
73
|
interface FileRoutesByPath {
|
|
74
|
+
'/landing': {
|
|
75
|
+
id: '/landing'
|
|
76
|
+
path: '/landing'
|
|
77
|
+
fullPath: '/landing'
|
|
78
|
+
preLoaderRoute: typeof LandingRouteImport
|
|
79
|
+
parentRoute: typeof rootRouteImport
|
|
80
|
+
}
|
|
54
81
|
'/dashboard': {
|
|
55
82
|
id: '/dashboard'
|
|
56
83
|
path: '/dashboard'
|
|
@@ -65,12 +92,21 @@ declare module '@tanstack/react-router' {
|
|
|
65
92
|
preLoaderRoute: typeof IndexRouteImport
|
|
66
93
|
parentRoute: typeof rootRouteImport
|
|
67
94
|
}
|
|
95
|
+
'/share/$id': {
|
|
96
|
+
id: '/share/$id'
|
|
97
|
+
path: '/share/$id'
|
|
98
|
+
fullPath: '/share/$id'
|
|
99
|
+
preLoaderRoute: typeof ShareIdRouteImport
|
|
100
|
+
parentRoute: typeof rootRouteImport
|
|
101
|
+
}
|
|
68
102
|
}
|
|
69
103
|
}
|
|
70
104
|
|
|
71
105
|
const rootRouteChildren: RootRouteChildren = {
|
|
72
106
|
IndexRoute: IndexRoute,
|
|
73
107
|
DashboardRoute: DashboardRoute,
|
|
108
|
+
LandingRoute: LandingRoute,
|
|
109
|
+
ShareIdRoute: ShareIdRoute,
|
|
74
110
|
}
|
|
75
111
|
export const routeTree = rootRouteImport
|
|
76
112
|
._addFileChildren(rootRouteChildren)
|
package/src/routes/__root.tsx
CHANGED
|
@@ -37,10 +37,12 @@ function RootComponent() {
|
|
|
37
37
|
<ThemeProvider attribute="class" defaultTheme="dark" disableTransitionOnChange storageKey="vite-ui-theme">
|
|
38
38
|
<div className="grid grid-rows-[auto_1fr] h-svh">
|
|
39
39
|
<Header />
|
|
40
|
+
{/* @ts-ignore - React 19 type incompatibility */}
|
|
40
41
|
<Outlet />
|
|
41
42
|
</div>
|
|
42
43
|
<Toaster richColors />
|
|
43
44
|
</ThemeProvider>
|
|
45
|
+
{/* @ts-ignore - React 19 type incompatibility */}
|
|
44
46
|
<TanStackRouterDevtools position="bottom-left" />
|
|
45
47
|
</>
|
|
46
48
|
)
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router"
|
|
2
|
+
import { Button } from "@/components/ui/button"
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
4
|
+
import { useState } from "react"
|
|
5
|
+
|
|
6
|
+
export const Route = createFileRoute("/landing")({
|
|
7
|
+
component: LandingPage,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const GITHUB_REPO = "https://github.com/Noisemaker111/Jonsoc"
|
|
11
|
+
|
|
12
|
+
function LandingPage() {
|
|
13
|
+
const [copied, setCopied] = useState(false)
|
|
14
|
+
|
|
15
|
+
const copyInstallCommand = () => {
|
|
16
|
+
navigator.clipboard.writeText("bun add -g jonsoc")
|
|
17
|
+
setCopied(true)
|
|
18
|
+
setTimeout(() => setCopied(false), 2000)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div className="min-h-screen bg-gradient-to-b from-background to-muted">
|
|
23
|
+
{/* Hero Section */}
|
|
24
|
+
<div className="container mx-auto max-w-6xl px-4 pt-20 pb-16">
|
|
25
|
+
<div className="text-center">
|
|
26
|
+
<h1 className="mb-6 text-5xl font-bold tracking-tight sm:text-6xl lg:text-7xl">jonsoc</h1>
|
|
27
|
+
<p className="mx-auto mb-8 max-w-2xl text-xl text-muted-foreground">
|
|
28
|
+
AI-powered development tool — an open source fork of OpenCode (opencode.ai)
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
{/* Install Command */}
|
|
32
|
+
<div className="mx-auto mb-8 max-w-md">
|
|
33
|
+
<div className="rounded-lg border bg-card p-4 font-mono text-sm shadow-sm">
|
|
34
|
+
<div className="flex items-center justify-between">
|
|
35
|
+
<code className="text-primary">bun add -g jonsoc</code>
|
|
36
|
+
<Button variant="ghost" size="sm" onClick={copyInstallCommand} className="h-8">
|
|
37
|
+
{copied ? "Copied!" : "Copy"}
|
|
38
|
+
</Button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
<p className="mt-2 text-xs text-muted-foreground">
|
|
42
|
+
Or use npm: <code className="rounded bg-muted px-1 py-0.5">npm install -g jonsoc</code>
|
|
43
|
+
</p>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
{/* CTA Buttons */}
|
|
47
|
+
<div className="flex flex-wrap items-center justify-center gap-4">
|
|
48
|
+
<a href={GITHUB_REPO} target="_blank" rel="noopener noreferrer">
|
|
49
|
+
<Button size="lg" className="gap-2">
|
|
50
|
+
<svg
|
|
51
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
52
|
+
width="20"
|
|
53
|
+
height="20"
|
|
54
|
+
viewBox="0 0 24 24"
|
|
55
|
+
fill="none"
|
|
56
|
+
stroke="currentColor"
|
|
57
|
+
strokeWidth="2"
|
|
58
|
+
strokeLinecap="round"
|
|
59
|
+
strokeLinejoin="round"
|
|
60
|
+
>
|
|
61
|
+
<path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4" />
|
|
62
|
+
<path d="M9 18c-4.51 2-5-2-7-2" />
|
|
63
|
+
</svg>
|
|
64
|
+
View on GitHub
|
|
65
|
+
</Button>
|
|
66
|
+
</a>
|
|
67
|
+
<a href="/dashboard">
|
|
68
|
+
<Button variant="outline" size="lg" className="gap-2">
|
|
69
|
+
Try Web App
|
|
70
|
+
</Button>
|
|
71
|
+
</a>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{/* Features Section */}
|
|
77
|
+
<div className="container mx-auto max-w-6xl px-4 py-16">
|
|
78
|
+
<h2 className="mb-12 text-center text-3xl font-bold">Features</h2>
|
|
79
|
+
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
|
80
|
+
<Card>
|
|
81
|
+
<CardHeader>
|
|
82
|
+
<CardTitle className="flex items-center gap-2 text-lg">
|
|
83
|
+
<svg className="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
84
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
|
|
85
|
+
</svg>
|
|
86
|
+
AI-Powered Development
|
|
87
|
+
</CardTitle>
|
|
88
|
+
</CardHeader>
|
|
89
|
+
<CardContent className="text-muted-foreground">
|
|
90
|
+
Intelligent code assistance with multiple AI providers and models.
|
|
91
|
+
</CardContent>
|
|
92
|
+
</Card>
|
|
93
|
+
|
|
94
|
+
<Card>
|
|
95
|
+
<CardHeader>
|
|
96
|
+
<CardTitle className="flex items-center gap-2 text-lg">
|
|
97
|
+
<svg className="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
98
|
+
<path
|
|
99
|
+
strokeLinecap="round"
|
|
100
|
+
strokeLinejoin="round"
|
|
101
|
+
strokeWidth={2}
|
|
102
|
+
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
103
|
+
/>
|
|
104
|
+
</svg>
|
|
105
|
+
Terminal UI
|
|
106
|
+
</CardTitle>
|
|
107
|
+
</CardHeader>
|
|
108
|
+
<CardContent className="text-muted-foreground">
|
|
109
|
+
Built-in TUI with syntax highlighting, file browser, and session management.
|
|
110
|
+
</CardContent>
|
|
111
|
+
</Card>
|
|
112
|
+
|
|
113
|
+
<Card>
|
|
114
|
+
<CardHeader>
|
|
115
|
+
<CardTitle className="flex items-center gap-2 text-lg">
|
|
116
|
+
<svg className="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
117
|
+
<path
|
|
118
|
+
strokeLinecap="round"
|
|
119
|
+
strokeLinejoin="round"
|
|
120
|
+
strokeWidth={2}
|
|
121
|
+
d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
|
|
122
|
+
/>
|
|
123
|
+
</svg>
|
|
124
|
+
Share Sessions
|
|
125
|
+
</CardTitle>
|
|
126
|
+
</CardHeader>
|
|
127
|
+
<CardContent className="text-muted-foreground">
|
|
128
|
+
Share your AI sessions with others via public links. Great for collaboration.
|
|
129
|
+
</CardContent>
|
|
130
|
+
</Card>
|
|
131
|
+
|
|
132
|
+
<Card>
|
|
133
|
+
<CardHeader>
|
|
134
|
+
<CardTitle className="flex items-center gap-2 text-lg">
|
|
135
|
+
<svg className="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
136
|
+
<path
|
|
137
|
+
strokeLinecap="round"
|
|
138
|
+
strokeLinejoin="round"
|
|
139
|
+
strokeWidth={2}
|
|
140
|
+
d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"
|
|
141
|
+
/>
|
|
142
|
+
</svg>
|
|
143
|
+
Multiple Providers
|
|
144
|
+
</CardTitle>
|
|
145
|
+
</CardHeader>
|
|
146
|
+
<CardContent className="text-muted-foreground">
|
|
147
|
+
Support for OpenAI, Anthropic, Google, and many more AI providers.
|
|
148
|
+
</CardContent>
|
|
149
|
+
</Card>
|
|
150
|
+
|
|
151
|
+
<Card>
|
|
152
|
+
<CardHeader>
|
|
153
|
+
<CardTitle className="flex items-center gap-2 text-lg">
|
|
154
|
+
<svg className="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
155
|
+
<path
|
|
156
|
+
strokeLinecap="round"
|
|
157
|
+
strokeLinejoin="round"
|
|
158
|
+
strokeWidth={2}
|
|
159
|
+
d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"
|
|
160
|
+
/>
|
|
161
|
+
</svg>
|
|
162
|
+
Open Source
|
|
163
|
+
</CardTitle>
|
|
164
|
+
</CardHeader>
|
|
165
|
+
<CardContent className="text-muted-foreground">
|
|
166
|
+
MIT licensed. Forked from OpenCode with gratitude. Build with the community.
|
|
167
|
+
</CardContent>
|
|
168
|
+
</Card>
|
|
169
|
+
|
|
170
|
+
<Card>
|
|
171
|
+
<CardHeader>
|
|
172
|
+
<CardTitle className="flex items-center gap-2 text-lg">
|
|
173
|
+
<svg className="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
174
|
+
<path
|
|
175
|
+
strokeLinecap="round"
|
|
176
|
+
strokeLinejoin="round"
|
|
177
|
+
strokeWidth={2}
|
|
178
|
+
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
|
179
|
+
/>
|
|
180
|
+
</svg>
|
|
181
|
+
Privacy First
|
|
182
|
+
</CardTitle>
|
|
183
|
+
</CardHeader>
|
|
184
|
+
<CardContent className="text-muted-foreground">
|
|
185
|
+
Your data stays local. Self-host the backend or use enterprise features.
|
|
186
|
+
</CardContent>
|
|
187
|
+
</Card>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
|
|
191
|
+
{/* Downloads Section */}
|
|
192
|
+
<div className="container mx-auto max-w-6xl px-4 py-16">
|
|
193
|
+
<h2 className="mb-12 text-center text-3xl font-bold">Download</h2>
|
|
194
|
+
<div className="mx-auto max-w-2xl">
|
|
195
|
+
<Card>
|
|
196
|
+
<CardHeader>
|
|
197
|
+
<CardTitle>Installation Options</CardTitle>
|
|
198
|
+
</CardHeader>
|
|
199
|
+
<CardContent className="space-y-4">
|
|
200
|
+
<div className="rounded-lg border bg-muted p-4">
|
|
201
|
+
<p className="mb-2 font-medium">Via Bun (Recommended)</p>
|
|
202
|
+
<code className="block rounded bg-background p-2 font-mono text-sm">bun add -g jonsoc</code>
|
|
203
|
+
</div>
|
|
204
|
+
<div className="rounded-lg border bg-muted p-4">
|
|
205
|
+
<p className="mb-2 font-medium">Via npm</p>
|
|
206
|
+
<code className="block rounded bg-background p-2 font-mono text-sm">npm install -g jonsoc</code>
|
|
207
|
+
</div>
|
|
208
|
+
<div className="rounded-lg border bg-muted p-4">
|
|
209
|
+
<p className="mb-2 font-medium">Via curl (Linux/macOS)</p>
|
|
210
|
+
<code className="block rounded bg-background p-2 font-mono text-sm">
|
|
211
|
+
curl -fsSL https://jonsoc.com/install | bash
|
|
212
|
+
</code>
|
|
213
|
+
</div>
|
|
214
|
+
<p className="text-center text-sm text-muted-foreground">
|
|
215
|
+
Supports: macOS (ARM64), Linux (x64), Windows (x64)
|
|
216
|
+
</p>
|
|
217
|
+
</CardContent>
|
|
218
|
+
</Card>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
{/* Footer */}
|
|
223
|
+
<footer className="border-t py-8">
|
|
224
|
+
<div className="container mx-auto max-w-6xl px-4 text-center text-sm text-muted-foreground">
|
|
225
|
+
<p>Built with gratitude for the OpenCode team. MIT License.</p>
|
|
226
|
+
<p className="mt-2">
|
|
227
|
+
<a href={GITHUB_REPO} className="hover:text-primary hover:underline">
|
|
228
|
+
GitHub
|
|
229
|
+
</a>
|
|
230
|
+
{" • "}
|
|
231
|
+
<a href="/dashboard" className="hover:text-primary hover:underline">
|
|
232
|
+
Dashboard
|
|
233
|
+
</a>
|
|
234
|
+
</p>
|
|
235
|
+
</div>
|
|
236
|
+
</footer>
|
|
237
|
+
</div>
|
|
238
|
+
)
|
|
239
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { createFileRoute, useParams } from "@tanstack/react-router"
|
|
2
|
+
import { useQuery } from "convex/react"
|
|
3
|
+
import { api } from "@jonsoc/convex"
|
|
4
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
5
|
+
import { Skeleton } from "@/components/ui/skeleton"
|
|
6
|
+
|
|
7
|
+
export const Route = createFileRoute("/share/$id")({
|
|
8
|
+
component: ShareViewerPage,
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
function ShareViewerPage() {
|
|
12
|
+
const { id } = useParams({ from: "/share/$id" })
|
|
13
|
+
const shareData = useQuery(api.share.getPublic, { slug: id })
|
|
14
|
+
|
|
15
|
+
if (shareData === undefined) {
|
|
16
|
+
return (
|
|
17
|
+
<div className="container mx-auto max-w-4xl px-4 py-8">
|
|
18
|
+
<Card>
|
|
19
|
+
<CardHeader>
|
|
20
|
+
<Skeleton className="h-8 w-64" />
|
|
21
|
+
</CardHeader>
|
|
22
|
+
<CardContent className="space-y-4">
|
|
23
|
+
<Skeleton className="h-20 w-full" />
|
|
24
|
+
<Skeleton className="h-20 w-full" />
|
|
25
|
+
<Skeleton className="h-20 w-full" />
|
|
26
|
+
</CardContent>
|
|
27
|
+
</Card>
|
|
28
|
+
</div>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (shareData === null) {
|
|
33
|
+
return (
|
|
34
|
+
<div className="container mx-auto max-w-4xl px-4 py-8">
|
|
35
|
+
<Card>
|
|
36
|
+
<CardHeader>
|
|
37
|
+
<CardTitle>Share Not Found</CardTitle>
|
|
38
|
+
</CardHeader>
|
|
39
|
+
<CardContent>
|
|
40
|
+
<p className="text-muted-foreground">This share link is invalid, has been deleted, or is not public.</p>
|
|
41
|
+
</CardContent>
|
|
42
|
+
</Card>
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Group data by type
|
|
48
|
+
const session = shareData.data.find((d: any) => d.type === "session")?.data
|
|
49
|
+
const messages = shareData.data
|
|
50
|
+
.filter((d: any) => d.type === "message")
|
|
51
|
+
.sort((a: any, b: any) => {
|
|
52
|
+
const aTime = a.data?.createdAt || 0
|
|
53
|
+
const bTime = b.data?.createdAt || 0
|
|
54
|
+
return aTime - bTime
|
|
55
|
+
})
|
|
56
|
+
const diffs = shareData.data.find((d: any) => d.type === "session_diff")?.data || []
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<div className="container mx-auto max-w-4xl px-4 py-8">
|
|
60
|
+
{/* Share Header */}
|
|
61
|
+
<Card className="mb-6">
|
|
62
|
+
<CardHeader>
|
|
63
|
+
<CardTitle>{session?.title || "Untitled Session"}</CardTitle>
|
|
64
|
+
</CardHeader>
|
|
65
|
+
<CardContent>
|
|
66
|
+
<div className="flex flex-wrap gap-4 text-sm text-muted-foreground">
|
|
67
|
+
<span>ID: {shareData.id}</span>
|
|
68
|
+
<span>Created: {new Date(shareData.createdAt).toLocaleString()}</span>
|
|
69
|
+
{shareData.model && <span>Model: {shareData.model}</span>}
|
|
70
|
+
</div>
|
|
71
|
+
</CardContent>
|
|
72
|
+
</Card>
|
|
73
|
+
|
|
74
|
+
{/* Messages */}
|
|
75
|
+
{messages.length > 0 && (
|
|
76
|
+
<Card className="mb-6">
|
|
77
|
+
<CardHeader>
|
|
78
|
+
<CardTitle>Conversation</CardTitle>
|
|
79
|
+
</CardHeader>
|
|
80
|
+
<CardContent className="space-y-4">
|
|
81
|
+
{messages.map((msg: any, idx: number) => (
|
|
82
|
+
<div
|
|
83
|
+
key={idx}
|
|
84
|
+
className={`rounded-lg border p-4 ${
|
|
85
|
+
msg.data?.role === "user"
|
|
86
|
+
? "bg-muted ml-8"
|
|
87
|
+
: msg.data?.role === "assistant"
|
|
88
|
+
? "bg-card mr-8"
|
|
89
|
+
: "bg-card"
|
|
90
|
+
}`}
|
|
91
|
+
>
|
|
92
|
+
<div className="mb-2 text-xs font-medium uppercase text-muted-foreground">
|
|
93
|
+
{msg.data?.role || "unknown"}
|
|
94
|
+
</div>
|
|
95
|
+
<div className="prose prose-sm max-w-none dark:prose-invert">{msg.data?.content || "[No content]"}</div>
|
|
96
|
+
</div>
|
|
97
|
+
))}
|
|
98
|
+
</CardContent>
|
|
99
|
+
</Card>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
{/* File Changes */}
|
|
103
|
+
{diffs.length > 0 && (
|
|
104
|
+
<Card>
|
|
105
|
+
<CardHeader>
|
|
106
|
+
<CardTitle>File Changes ({diffs.length})</CardTitle>
|
|
107
|
+
</CardHeader>
|
|
108
|
+
<CardContent>
|
|
109
|
+
<ul className="space-y-2">
|
|
110
|
+
{diffs.map((diff: any, idx: number) => (
|
|
111
|
+
<li key={idx} className="flex items-center gap-2 text-sm">
|
|
112
|
+
<span
|
|
113
|
+
className={`inline-block h-2 w-2 rounded-full ${
|
|
114
|
+
diff.status === "added"
|
|
115
|
+
? "bg-green-500"
|
|
116
|
+
: diff.status === "deleted"
|
|
117
|
+
? "bg-red-500"
|
|
118
|
+
: diff.status === "modified"
|
|
119
|
+
? "bg-yellow-500"
|
|
120
|
+
: "bg-gray-500"
|
|
121
|
+
}`}
|
|
122
|
+
/>
|
|
123
|
+
<code className="rounded bg-muted px-1 py-0.5 text-xs">{diff.path}</code>
|
|
124
|
+
<span className="text-muted-foreground">({diff.status})</span>
|
|
125
|
+
</li>
|
|
126
|
+
))}
|
|
127
|
+
</ul>
|
|
128
|
+
</CardContent>
|
|
129
|
+
</Card>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
{/* Footer */}
|
|
133
|
+
<div className="mt-8 text-center text-sm text-muted-foreground">
|
|
134
|
+
<p>
|
|
135
|
+
Shared via jonsoc •{" "}
|
|
136
|
+
<a
|
|
137
|
+
href="https://github.com/Noisemaker111/Jonsoc"
|
|
138
|
+
target="_blank"
|
|
139
|
+
rel="noopener noreferrer"
|
|
140
|
+
className="hover:text-primary hover:underline"
|
|
141
|
+
>
|
|
142
|
+
GitHub
|
|
143
|
+
</a>
|
|
144
|
+
</p>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
)
|
|
148
|
+
}
|