Skip to content

Commit ad70e55

Browse files
authored
Merge pull request supabase-community#32 from supabase-community/feat/themes
Themes support and improved UI
2 parents 11dde05 + 3cf8f98 commit ad70e55

26 files changed

+954
-681
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ next-env.d.ts
3939
dbs/
4040
tls/
4141
dist/
42+
43+
.env

apps/postgres-new/app/globals.css

Lines changed: 68 additions & 329 deletions
Large diffs are not rendered by default.

apps/postgres-new/app/layout.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
import 'katex/dist/katex.min.css'
21
import './globals.css'
3-
2+
import 'katex/dist/katex.min.css'
43
import type { Metadata } from 'next'
5-
import { Inter } from 'next/font/google'
4+
import { Inter as FontSans } from 'next/font/google'
65
import Layout from '~/components/layout'
76
import Providers from '~/components/providers'
87
import { cn } from '~/lib/utils'
98

10-
const inter = Inter({ subsets: ['latin'] })
9+
const fontSans = FontSans({
10+
subsets: ['latin'],
11+
variable: '--font-sans',
12+
})
1113

1214
export const metadata: Metadata = {
1315
title: 'Postgres Sandbox',
@@ -21,7 +23,7 @@ export default function RootLayout({
2123
}>) {
2224
return (
2325
<html lang="en">
24-
<body className={cn(inter.className)}>
26+
<body className={cn('bg-background font-sans antialiased', fontSans.variable)}>
2527
<Providers>
2628
<Layout>{children}</Layout>
2729
</Providers>

apps/postgres-new/components/chat-message.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function ChatMessage({ message, isLast }: ChatMessageProps) {
3939
x: 0,
4040
},
4141
}}
42-
className="self-end px-5 py-2.5 text-base rounded-3xl bg-neutral-100 whitespace-pre-wrap"
42+
className="self-end px-5 py-2.5 text-base rounded-3xl bg-border text-foreground whitespace-pre-wrap"
4343
>
4444
{message.content}
4545
</m.div>
@@ -50,7 +50,7 @@ function ChatMessage({ message, isLast }: ChatMessageProps) {
5050
remarkPlugins={[remarkGfm, [remarkMath, { singleDollarTextMath: false }]]}
5151
rehypePlugins={[[rehypeKatex, { output: 'html' }]]}
5252
components={{ ...markdownComponents, img: () => null }}
53-
className="prose [&_.katex-display>.katex]:text-left"
53+
className="prose prose-xs text-base [&_.katex-display>.katex]:text-left"
5454
>
5555
{message.content}
5656
</ReactMarkdown>
@@ -111,8 +111,13 @@ const NextImageHandler = (props: any) => {
111111
}
112112

113113
const markdownComponents = {
114-
mono: (props: any) => <code className="text-sm">{props.children}</code>,
114+
mono: (props: any) => <code className="text-sm not-prose">{props.children}</code>,
115115
code: (props: any) => <CodeBlock {...props} />,
116+
pre: (props: any) => (
117+
<pre className="not-prose">
118+
<CodeBlock {...props} />
119+
</pre>
120+
),
116121
img: (props: any) => NextImageHandler(props),
117122
Image: (props: any) => NextImageHandler(props),
118123
}

apps/postgres-new/components/chat.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export function getInitialMessages(tables: TablesData): Message[] {
4848

4949
export default function Chat() {
5050
const { user, isLoadingUser } = useApp()
51+
const [inputFocusState, setInputFocusState] = useState(false)
5152

5253
const {
5354
databaseId,
@@ -125,7 +126,7 @@ export default function Chat() {
125126
cursorElement: (
126127
<m.div
127128
layoutId={nextMessageId}
128-
className="px-5 py-2.5 text-base rounded-full bg-neutral-100 flex gap-2 items-center shadow-xl z-50"
129+
className="px-5 py-2.5 text-foreground rounded-full bg-border flex gap-2 items-center shadow-xl z-50"
129130
>
130131
<Paperclip size={14} /> Add file to chat
131132
</m.div>
@@ -343,7 +344,11 @@ export default function Chat() {
343344
)}
344345
</AnimatePresence>
345346
<form
346-
className="flex items-end py-2 px-3 rounded-[28px] bg-neutral-100 w-full max-w-4xl"
347+
className={cn(
348+
'flex py-2 px-3 rounded-[28px] bg-muted/50 border w-full max-w-4xl items-center gap-3',
349+
inputFocusState && 'border-muted-foreground',
350+
'transition'
351+
)}
347352
onSubmit={handleFormSubmit}
348353
>
349354
{/*
@@ -366,8 +371,10 @@ export default function Chat() {
366371
</m.div>
367372
)}
368373
<Button
369-
className="w-8 h-8 p-1.5 my-1 bg-inherit transition-colors"
370374
type="button"
375+
variant={'ghost'}
376+
className="w-8 h-8 text-muted-foreground hover:text-foreground focus:text-foreground"
377+
size="icon"
371378
onClick={(e) => {
372379
e.preventDefault()
373380

@@ -400,17 +407,23 @@ export default function Chat() {
400407
}}
401408
disabled={isLoading || !user}
402409
>
403-
<Paperclip size={20} />
410+
<Paperclip size={16} strokeWidth={1.3} />
404411
</Button>
405412
<textarea
406413
ref={inputRef}
407414
id="input"
408415
name="prompt"
409416
autoComplete="off"
410-
className="flex-grow border-none focus-visible:ring-0 text-base bg-inherit placeholder:text-neutral-400 resize-none"
417+
className="flex-grow border-none focus-visible:ring-0 text-base placeholder:text-muted-foreground/50 bg-transparent resize-none outline-none"
411418
value={input}
412419
onChange={handleInputChange}
413420
placeholder="Message AI or write SQL"
421+
onFocus={(e) => {
422+
setInputFocusState(true)
423+
}}
424+
onBlur={(e) => {
425+
setInputFocusState(false)
426+
}}
414427
autoFocus
415428
disabled={!user}
416429
rows={Math.min(input.split('\n').length, 10)}

apps/postgres-new/components/code-accordion.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DatabaseZap } from 'lucide-react'
1+
import { CircleX, DatabaseZap } from 'lucide-react'
22
import {
33
Accordion,
44
AccordionContent,
@@ -28,26 +28,43 @@ export default function CodeAccordion({
2828
<AccordionItem
2929
value="item-1"
3030
className={cn(
31-
'border-2 border-neutral-100 bg-neutral-50 px-3 py-2 rounded-md',
32-
error ? 'bg-destructive-300' : undefined,
31+
'border rounded-md overflow-hidden',
32+
error ? 'border-destructive' : undefined,
3333
className
3434
)}
3535
>
36-
<AccordionTrigger className="p-0 gap-2">
36+
<AccordionTrigger
37+
className={cn(
38+
'p-0 gap-2 px-3 py-2',
39+
error
40+
? 'bg-destructive border-destructive [&_svg]:text-destructive-foreground'
41+
: undefined
42+
)}
43+
>
3744
<div className="flex gap-2 items-center font-normal text-lighter text-sm">
38-
<DatabaseZap size={14} />
39-
{title}
45+
{error ? (
46+
<CircleX
47+
size={14}
48+
className={cn('text-muted-foreground', error && 'text-destructive-foreground')}
49+
/>
50+
) : (
51+
<DatabaseZap
52+
size={14}
53+
className={cn('text-muted-foreground', error && 'text-destructive-foreground')}
54+
/>
55+
)}
56+
<span className={cn(error ? 'text-destructive-foreground' : undefined)}>{title}</span>
4057
</div>
4158
</AccordionTrigger>
42-
<AccordionContent className="py-2 [&_>div]:pb-0 flex flex-col gap-2">
59+
<AccordionContent className="py-2 [&_>div]:pb-0 flex flex-col gap-2 bg-background px-3">
4360
<CodeBlock
4461
className={cn(`language-${language}`, 'border-none px-0 pb-4 !bg-inherit')}
4562
hideLineNumbers
4663
hideCopy
4764
>
4865
{code}
4966
</CodeBlock>
50-
{error && <div className="text-destructive-600 text-xs">{error}</div>}
67+
{error && <div className="text-red-600 text-xs">{error}</div>}
5168
</AccordionContent>
5269
</AccordionItem>
5370
</Accordion>

apps/postgres-new/components/ide.tsx

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { cn } from '~/lib/utils'
1616
import { useApp } from './app-provider'
1717
import SchemaGraph from './schema/graph'
1818
import { useWorkspace } from './workspace'
19+
import { buttonVariants } from './ui/button'
1920

2021
const initialMigrationSql = '-- Migrations will appear here as you chat with AI\n'
2122
const initialSeedSql = '-- Seeds will appear here as you chat with AI\n'
@@ -105,28 +106,56 @@ export default function IDE({ children, className }: IDEProps) {
105106
value={tab}
106107
onValueChange={(tab) => setTab(tabsSchema.parse(tab))}
107108
>
108-
<TabsList className="grid w-full grid-cols-3 lg:grid-cols-2">
109+
<TabsList className="grid w-full grid-cols-3 lg:grid-cols-2 !h-min bg-muted">
109110
{isSmallBreakpoint && (
110-
<TabsTrigger value="chat" className="flex items-center gap-1">
111+
<TabsTrigger
112+
value="chat"
113+
className={cn(
114+
buttonVariants({ variant: tab === 'chat' ? 'default' : 'ghost' }),
115+
tab === 'chat' && '!shadow-sm',
116+
'gap-2'
117+
)}
118+
>
111119
<MessageSquareMore size={14} />
112-
<span className="hidden xs:inline">Chat</span>
120+
<span className="hidden sm:inline">Chat</span>
113121
</TabsTrigger>
114122
)}
115-
<TabsTrigger value="diagram" className="flex items-center gap-1">
123+
<TabsTrigger
124+
value="diagram"
125+
className={cn(
126+
buttonVariants({ variant: tab === 'diagram' ? 'default' : 'ghost' }),
127+
tab === 'diagram' && '!shadow-sm',
128+
'gap-2'
129+
)}
130+
>
116131
<Workflow size={14} />
117-
<span className="hidden xs:inline">Diagram</span>
132+
<span className="hidden sm:inline">Diagram</span>
118133
</TabsTrigger>
119-
<TabsTrigger value="migrations" className="flex items-center gap-1">
134+
<TabsTrigger
135+
value="migrations"
136+
className={cn(
137+
buttonVariants({ variant: tab === 'migrations' ? 'default' : 'ghost' }),
138+
tab === 'migrations' && '!shadow-sm',
139+
'gap-2'
140+
)}
141+
>
120142
<FileCode size={14} />
121-
<span className="hidden xs:inline">Migrations</span>
143+
<span className="hidden sm:inline">Migrations</span>
122144
</TabsTrigger>
123145
{/* Temporarily hide seeds until we get pg_dump working */}
124-
{false && (
125-
<TabsTrigger value="seeds" className="flex items-center gap-1">
146+
{/* {false && (
147+
<TabsTrigger
148+
value="seeds"
149+
className={cn(
150+
buttonVariants({ variant: tab === 'seeds' ? 'default' : 'ghost' }),
151+
tab === 'seeds' && '!shadow-sm',
152+
'gap-2'
153+
)}
154+
>
126155
<Sprout size={14} />
127-
<span className="hidden xs:inline">Seeds</span>
156+
<span className="hidden sm:inline">Seeds</span>
128157
</TabsTrigger>
129-
)}
158+
)} */}
130159
</TabsList>
131160

132161
{isSmallBreakpoint && (
@@ -234,22 +263,16 @@ export default function IDE({ children, className }: IDEProps) {
234263
}
235264

236265
function Footer() {
237-
const { pgliteVersion, pgVersion } = useApp()
238266
return (
239-
<div className="flex flex-col pb-1 text-xs text-neutral-500 text-center justify-center">
240-
{pgliteVersion && (
241-
<span>
242-
<a
243-
className="underline"
244-
href="https://github.com/electric-sql/pglite"
245-
target="_blank"
246-
rel="noopener noreferrer"
247-
>
248-
PGlite
249-
</a>{' '}
250-
{pgliteVersion} {pgVersion && <>(PG {pgVersion})</>}
251-
</span>
252-
)}
267+
<div className="flex flex-row gap-1 pb-1 text-xs text-neutral-500 text-center justify-center">
268+
<a
269+
className="underline cursor-pointer"
270+
href="https://github.com/supabase-community/postgres-new"
271+
target="_blank"
272+
rel="noopener noreferrer"
273+
>
274+
Learn about postgres.new
275+
</a>
253276
</div>
254277
)
255278
}

apps/postgres-new/components/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ export default function Layout({ children }: LayoutProps) {
2828
there.
2929
</div>
3030
)}
31-
<div className="flex-1 flex flex-col lg:flex-row min-h-0">
31+
<main className="flex-1 flex flex-col lg:flex-row min-h-0">
3232
{/* TODO: make sidebar available on mobile */}
3333
{!isSmallBreakpoint && <Sidebar />}
3434
<m.div layout="position" className="w-full h-full min-w-0 min-h-0">
3535
{children}
3636
</m.div>
37-
</div>
37+
</main>
3838
</div>
3939
</TooltipProvider>
4040
</LazyMotion>

apps/postgres-new/components/markdown-accordion.tsx

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { DatabaseZap } from 'lucide-react'
1+
import { CircleX, Move3D } from 'lucide-react'
22
import ReactMarkdown from 'react-markdown'
33
import remarkGfm from 'remark-gfm'
44
import {
@@ -27,25 +27,42 @@ export default function MarkdownAccordion({
2727
<AccordionItem
2828
value="item-1"
2929
className={cn(
30-
'border-2 border-neutral-100 bg-neutral-50 px-3 py-2 rounded-md',
31-
error ? 'bg-destructive-300' : undefined,
30+
'border rounded-md overflow-hidden',
31+
error ? 'border-destructive' : undefined,
3232
className
3333
)}
3434
>
35-
<AccordionTrigger className="p-0 gap-2">
35+
<AccordionTrigger
36+
className={cn(
37+
'p-0 gap-2 px-3 py-2',
38+
error
39+
? 'bg-destructive border-destructive [&_svg]:text-destructive-foreground'
40+
: undefined
41+
)}
42+
>
3643
<div className="flex gap-2 items-center font-normal text-lighter text-sm">
37-
<DatabaseZap size={14} />
38-
{title}
44+
{error ? (
45+
<CircleX
46+
size={14}
47+
className={cn('text-muted-foreground', error && 'text-destructive-foreground')}
48+
/>
49+
) : (
50+
<Move3D
51+
size={14}
52+
className={cn('text-muted-foreground', error && 'text-destructive-foreground')}
53+
/>
54+
)}
55+
<span className={cn(error ? 'text-destructive-foreground' : undefined)}>{title}</span>
3956
</div>
4057
</AccordionTrigger>
41-
<AccordionContent className="py-2 [&_>div]:pb-0 flex flex-col gap-2">
58+
<AccordionContent className="py-2 [&_>div]:pb-0 flex flex-col gap-2 bg-background px-3">
4259
<ReactMarkdown
4360
remarkPlugins={[remarkGfm]}
4461
className="prose text-xs mt-2 [&_ul>li::before]:top-2 [&_ol>li::before]:top-0"
4562
>
4663
{content}
4764
</ReactMarkdown>
48-
{error && <div className="text-destructive-600 text-xs">{error}</div>}
65+
{error && <div className="text-red-600 text-xs">{error}</div>}
4966
</AccordionContent>
5067
</AccordionItem>
5168
</Accordion>

apps/postgres-new/components/providers.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
'use client'
22

33
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
4-
import { ThemeProvider } from 'next-themes'
4+
55
import { PropsWithChildren } from 'react'
66
import AppProvider from './app-provider'
7+
import { ThemeProvider } from './theme-provider'
78

89
const queryClient = new QueryClient()
910

1011
export default function Providers({ children }: PropsWithChildren) {
1112
return (
1213
// Force theme until we implement dark mode
13-
<ThemeProvider forcedTheme="light">
14+
<ThemeProvider
15+
attribute="class"
16+
defaultTheme="system"
17+
storageKey="jonny"
18+
disableTransitionOnChange
19+
>
1420
<QueryClientProvider client={queryClient}>
1521
<AppProvider>{children}</AppProvider>
1622
</QueryClientProvider>

0 commit comments

Comments
 (0)