Skip to content

Commit c4f38a2

Browse files
authored
Merge pull request #24 from tinybirdco/sidebar
move grid to sidebar
2 parents ac3bbf4 + f902d01 commit c4f38a2

File tree

19 files changed

+313
-267
lines changed

19 files changed

+313
-267
lines changed

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@radix-ui/react-scroll-area": "^1.2.2",
1213
"@radix-ui/react-slot": "^1.1.1",
1314
"@radix-ui/react-tooltip": "^1.1.6",
1415
"class-variance-authority": "^0.7.1",

apps/web/pnpm-lock.yaml

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/web/src/app/[id]/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export default function AppPage({ params }: { params: Promise<{ id: string }> })
4444

4545
if (!token || !isValidToken) {
4646
return (
47-
<div className="container py-6">
47+
<div className="py-6">
4848
<TokenPrompt error={error} />
4949
</div>
5050
);
@@ -62,7 +62,7 @@ export default function AppPage({ params }: { params: Promise<{ id: string }> })
6262
const Component = toolState === 'available' ? tool_comps.Readme : tool_comps.Dashboard;
6363

6464
return (
65-
<div className="container py-6">
65+
<div className="py-6">
6666
<div className="flex flex-col gap-6">
6767
<div className="flex items-center gap-2">
6868
<h1 className="text-2xl font-bold">{TOOLS[id].name}</h1>

apps/web/src/app/layout.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { Metadata } from "next";
22
import { NuqsAdapter } from 'nuqs/adapters/next/app'
33
import { Geist, Geist_Mono } from "next/font/google";
4+
import { Sidebar } from "@/components/sidebar";
45
import "./globals.css";
56

67
const geistSans = Geist({
@@ -29,8 +30,13 @@ export default function RootLayout({
2930
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
3031
>
3132
<NuqsAdapter>
32-
<div className="container mx-auto p-6">
33-
{children}
33+
<div className="flex">
34+
<Sidebar />
35+
<div className="flex-1">
36+
<div className="container mx-auto p-6">
37+
{children}
38+
</div>
39+
</div>
3440
</div>
3541
</NuqsAdapter>
3642
</body>

apps/web/src/app/page.tsx

Lines changed: 16 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,177 +1,33 @@
11
"use client";
22

33
import { useQueryState } from 'nuqs';
4-
import { useState, useEffect, Suspense } from 'react';
5-
import { Card } from '@/components/ui/card';
6-
import Link from 'next/link';
7-
import { checkToolState, InvalidTokenError } from '@/lib/tinybird';
8-
import { TOOLS, type AppGridItem, type ToolState } from '@/lib/constants';
4+
import { Suspense } from 'react';
95
import TokenPrompt from '@/components/token-prompt';
10-
import { SectionHeader } from '@/components/section-header';
116

127
function HomeContent() {
13-
const [token, setToken] = useQueryState('token');
14-
const [toolStates, setToolStates] = useState<Record<string, ToolState>>({});
15-
const [isLoading, setIsLoading] = useState(false);
16-
const [error, setError] = useState<string>();
17-
const [isValidToken, setIsValidToken] = useState(false);
8+
const [token] = useQueryState('token');
189

19-
useEffect(() => {
20-
async function fetchToolStates() {
21-
if (!token) {
22-
setIsValidToken(false);
23-
return;
24-
}
25-
setIsLoading(true);
26-
setError(undefined);
27-
try {
28-
const states = await Promise.all(
29-
Object.values(TOOLS).map(async (app) => {
30-
const state = await checkToolState(token, app.ds);
31-
return [app.id, state] as const;
32-
})
33-
);
34-
setToolStates(Object.fromEntries(states));
35-
setIsValidToken(true);
36-
} catch (error) {
37-
if (error instanceof InvalidTokenError) {
38-
setError('Invalid token');
39-
setToken(null);
40-
setIsValidToken(false);
41-
} else {
42-
console.error('Failed to fetch tool states:', error);
43-
setError('Failed to fetch tool states');
44-
setIsValidToken(false);
45-
}
46-
} finally {
47-
setIsLoading(false);
48-
}
49-
}
50-
51-
fetchToolStates();
52-
}, [token, setToken]);
53-
54-
if (!token || !isValidToken) {
55-
return (
56-
<div className="container py-6">
57-
<TokenPrompt error={error} />
58-
</div>
59-
);
10+
if (!token) {
11+
return <TokenPrompt />;
6012
}
6113

6214
return (
63-
<div className="container py-6">
64-
{isLoading ? (
65-
<div className="flex items-center justify-center">
66-
<p className="text-lg font-semibold">Loading...</p>
67-
</div>
68-
) : (
69-
<div className="space-y-8">
70-
{/* Configured Apps */}
71-
{Object.values(TOOLS).some(app => toolStates[app.id] === 'configured') && (
72-
<div className="space-y-4">
73-
<SectionHeader
74-
title="Configured Apps"
75-
tooltip="These apps are fully set up and have data. They're ready to use!"
76-
/>
77-
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
78-
{Object.values(TOOLS)
79-
.filter(app => toolStates[app.id] === 'configured')
80-
.map(app => (
81-
<AppCard
82-
key={app.id}
83-
app={app}
84-
state={toolStates[app.id]}
85-
token={token}
86-
/>
87-
))}
88-
</div>
89-
</div>
90-
)}
91-
92-
{/* Installed Apps */}
93-
{Object.values(TOOLS).some(app => toolStates[app.id] === 'installed') && (
94-
<div className="space-y-4">
95-
<SectionHeader
96-
title="Installed Apps"
97-
tooltip="Your Tinybird Workspace has the Data Sources installed, but you're not receiving data. Click an app to learn how to add data."
98-
/>
99-
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
100-
{Object.values(TOOLS)
101-
.filter(app => toolStates[app.id] === 'installed')
102-
.map(app => (
103-
<AppCard
104-
key={app.id}
105-
app={app}
106-
state={toolStates[app.id]}
107-
token={token}
108-
/>
109-
))}
110-
</div>
111-
</div>
112-
)}
113-
114-
{/* Available Apps */}
115-
<div className="space-y-4">
116-
<SectionHeader
117-
title="Available Apps"
118-
tooltip="Your Tinybird Workspace doesn't have the Data Sources installed yet. Click an app to learn how to install it."
119-
/>
120-
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
121-
{Object.values(TOOLS)
122-
.filter(app => !toolStates[app.id] || toolStates[app.id] === 'available')
123-
.map(app => (
124-
<AppCard
125-
key={app.id}
126-
app={app}
127-
state={toolStates[app.id] || 'available'}
128-
token={token}
129-
/>
130-
))}
131-
</div>
132-
</div>
133-
</div>
134-
)}
15+
<div className="py-6">
16+
<div className="space-y-4">
17+
<h1 className="text-2xl font-bold">Welcome to Tinynest</h1>
18+
<p className="text-muted-foreground">
19+
Select an app from the sidebar to get started. Apps are organized by their status:
20+
</p>
21+
<ul className="list-disc list-inside space-y-2 text-muted-foreground">
22+
<li><strong>Configured Apps</strong> - These apps are fully set up and have data. They&apos;re ready to use!</li>
23+
<li><strong>Installed Apps</strong> - Your Tinybird Workspace has the Data Sources installed, but you&apos;re not receiving data.</li>
24+
<li><strong>Available Apps</strong> - Your Tinybird Workspace doesn&apos;t have the Data Sources installed yet.</li>
25+
</ul>
26+
</div>
13527
</div>
13628
);
13729
}
13830

139-
function AppCard({
140-
app,
141-
state,
142-
token
143-
}: {
144-
app: AppGridItem;
145-
state: ToolState;
146-
token?: string;
147-
}) {
148-
const stateColors = {
149-
configured: 'border-green-500',
150-
installed: 'border-blue-500',
151-
available: ''
152-
};
153-
154-
return (
155-
<Link
156-
key={app.id}
157-
href={`/${app.id}${token ? `?token=${token}` : ''}`}
158-
>
159-
<Card className={`p-4 hover:bg-accent ${stateColors[state]}`}>
160-
<div className="flex items-center gap-4">
161-
<div className="text-2xl">{app.icon}</div>
162-
<div>
163-
<div className="flex items-center gap-2">
164-
<h3 className="font-semibold">{app.name}</h3>
165-
<span className="text-xs text-muted-foreground">({state})</span>
166-
</div>
167-
<p className="text-sm text-muted-foreground">{app.description}</p>
168-
</div>
169-
</div>
170-
</Card>
171-
</Link>
172-
);
173-
}
174-
17531
export default function Home() {
17632
return (
17733
<Suspense>

0 commit comments

Comments
 (0)