Skip to content

Commit edf6685

Browse files
authored
Merge pull request supabase-community#24 from supabase-community/feat/publish-waitlist
feat: publish waitlist
2 parents aa91015 + 5bbb6a9 commit edf6685

File tree

11 files changed

+599
-94
lines changed

11 files changed

+599
-94
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export interface CodeBlockProps {
4646
value?: string
4747
children?: string
4848
renderer?: SyntaxHighlighterProps['renderer']
49+
theme?: 'auto' | 'light' | 'dark'
4950
}
5051

5152
export const CodeBlock = ({
@@ -58,9 +59,10 @@ export const CodeBlock = ({
5859
hideCopy = false,
5960
hideLineNumbers = false,
6061
renderer,
62+
theme = 'auto',
6163
}: CodeBlockProps) => {
6264
const { resolvedTheme } = useTheme()
63-
const isDarkTheme = resolvedTheme?.includes('dark')!
65+
const isDarkTheme = theme === 'auto' ? resolvedTheme?.includes('dark')! : theme === 'dark'
6466
const monokaiTheme = monokaiCustomTheme(isDarkTheme)
6567

6668
const [copied, setCopied] = useState(false)
@@ -121,7 +123,7 @@ export const CodeBlock = ({
121123
// @ts-ignore
122124
style={monokaiTheme}
123125
className={cn(
124-
'code-block border border-surface p-4 w-full !my-0 !bg-surface-100',
126+
'code-block border border-surface p-4 w-full !my-0',
125127
`${!title ? '!rounded-md' : '!rounded-t-none !rounded-b-md'}`,
126128
`${!showLineNumbers ? 'pl-6' : ''}`,
127129
className

apps/postgres-new/components/sidebar.tsx

Lines changed: 169 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,24 @@ import {
1111
PackagePlus,
1212
Pencil,
1313
Trash2,
14+
Upload,
1415
} from 'lucide-react'
1516
import Link from 'next/link'
1617
import { useParams, useRouter } from 'next/navigation'
1718
import { useState } from 'react'
1819
import { Button } from '~/components/ui/button'
20+
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '~/components/ui/dialog'
1921
import { Popover, PopoverContent, PopoverTrigger } from '~/components/ui/popover'
2022
import { Tooltip, TooltipContent, TooltipTrigger } from '~/components/ui/tooltip'
2123
import { useDatabaseDeleteMutation } from '~/data/databases/database-delete-mutation'
2224
import { useDatabaseUpdateMutation } from '~/data/databases/database-update-mutation'
2325
import { useDatabasesQuery } from '~/data/databases/databases-query'
26+
import { usePublishWaitlistCreateMutation } from '~/data/publish-waitlist/publish-waitlist-create-mutation'
27+
import { useIsOnPublishWaitlistQuery } from '~/data/publish-waitlist/publish-waitlist-query'
2428
import { Database } from '~/lib/db'
2529
import { cn } from '~/lib/utils'
2630
import { useApp } from './app-provider'
31+
import { CodeBlock } from './code-block'
2732

2833
export default function Sidebar() {
2934
const { user, signOut } = useApp()
@@ -203,117 +208,192 @@ type DatabaseMenuItemProps = {
203208

204209
function DatabaseMenuItem({ database, isActive }: DatabaseMenuItemProps) {
205210
const router = useRouter()
211+
const { user } = useApp()
206212
const [isPopoverOpen, setIsPopoverOpen] = useState(false)
207213
const { mutateAsync: deleteDatabase } = useDatabaseDeleteMutation()
208214
const { mutateAsync: updateDatabase } = useDatabaseUpdateMutation()
209215

210216
const [isRenaming, setIsRenaming] = useState(false)
217+
const [isPublishDialogOpen, setIsPublishDialogOpen] = useState(false)
218+
219+
const { data: isOnPublishWaitlist } = useIsOnPublishWaitlistQuery()
220+
const { mutateAsync: joinPublishWaitlist } = usePublishWaitlistCreateMutation()
211221

212222
return (
213-
<Link
214-
data-active={isActive || isPopoverOpen}
215-
className={cn(
216-
'group text-sm w-full relative bg-inherit justify-start bg-neutral-100 hover:bg-neutral-200 flex gap-3 p-3 rounded-md overflow-hidden data-[active=true]:bg-neutral-200'
217-
)}
218-
href={`/db/${database.id}`}
219-
>
220-
<span className="text-nowrap">{database.name ?? 'My database'}</span>
221-
<div
222-
className={cn(
223-
'absolute right-0 top-0 bottom-0',
224-
'w-8 bg-gradient-to-l from-neutral-100 from-0%',
225-
'group-hover:w-16 group-hover:from-neutral-200 group-hover:from-50%',
226-
'group-data-[active=true]:w-16 group-data-[active=true]:from-neutral-200 group-data-[active=true]:from-50%'
227-
)}
228-
/>
229-
<Popover
223+
<>
224+
<Dialog
225+
open={isPublishDialogOpen}
230226
onOpenChange={(open) => {
231-
setIsPopoverOpen(open)
232-
if (!open) {
233-
setIsRenaming(false)
234-
}
227+
setIsPublishDialogOpen(open)
235228
}}
236-
open={isPopoverOpen}
237229
>
238-
<PopoverTrigger
239-
asChild
240-
onClick={(e) => {
241-
e.preventDefault()
242-
setIsPopoverOpen(true)
230+
<DialogContent className="max-w-2xl">
231+
<DialogHeader>
232+
<DialogTitle>Database publishing is in Private Alpha</DialogTitle>
233+
<div className="py-2 border-b" />
234+
</DialogHeader>
235+
<h2 className="font-medium">What is database publishing?</h2>
236+
<p>
237+
Publish your database so that it can be accessed outside the browser using any Postgres
238+
client:
239+
</p>
240+
<CodeBlock
241+
className="language-curl bg-neutral-800"
242+
language="curl"
243+
hideLineNumbers
244+
theme="dark"
245+
>
246+
{`psql "postgres://postgres:<password>@<your-unique-server>/postgres"`}
247+
</CodeBlock>
248+
<div className="flex justify-center items-center mt-3">
249+
<AnimatePresence initial={false}>
250+
{!isOnPublishWaitlist ? (
251+
<button
252+
className="px-4 py-3 bg-black text-white rounded-md"
253+
onClick={async () => {
254+
await joinPublishWaitlist()
255+
}}
256+
>
257+
Join Private Alpha
258+
</button>
259+
) : (
260+
<m.div
261+
className="px-4 py-3 border-2 rounded-md text-center border-dashed"
262+
variants={{
263+
hidden: { scale: 0 },
264+
show: { scale: 1 },
265+
}}
266+
initial="hidden"
267+
animate="show"
268+
>
269+
<h3 className="font-medium mb-2">🎉 You&apos;re on the list!</h3>
270+
<p>We&apos;ll let you know when you have access to publish.</p>
271+
</m.div>
272+
)}
273+
</AnimatePresence>
274+
</div>
275+
</DialogContent>
276+
</Dialog>
277+
278+
<Link
279+
data-active={isActive || isPopoverOpen}
280+
className={cn(
281+
'group text-sm w-full relative bg-inherit justify-start bg-neutral-100 hover:bg-neutral-200 flex gap-3 p-3 rounded-md overflow-hidden data-[active=true]:bg-neutral-200'
282+
)}
283+
href={`/db/${database.id}`}
284+
>
285+
<span className="text-nowrap">{database.name ?? 'My database'}</span>
286+
<div
287+
className={cn(
288+
'absolute right-0 top-0 bottom-0',
289+
'w-8 bg-gradient-to-l from-neutral-100 from-0%',
290+
'group-hover:w-16 group-hover:from-neutral-200 group-hover:from-50%',
291+
'group-data-[active=true]:w-16 group-data-[active=true]:from-neutral-200 group-data-[active=true]:from-50%'
292+
)}
293+
/>
294+
<Popover
295+
onOpenChange={(open) => {
296+
setIsPopoverOpen(open)
297+
if (!open) {
298+
setIsRenaming(false)
299+
}
243300
}}
301+
open={isPopoverOpen}
244302
>
245-
<div
246-
className={cn(
247-
'hidden group-hover:flex absolute right-0 top-0 bottom-0 p-2 opacity-50 items-center',
248-
isActive || isPopoverOpen ? 'flex' : undefined
249-
)}
303+
<PopoverTrigger
304+
asChild
305+
onClick={(e) => {
306+
e.preventDefault()
307+
setIsPopoverOpen(true)
308+
}}
250309
>
251-
<CircleEllipsis size={24} />
252-
</div>
253-
</PopoverTrigger>
310+
<div
311+
className={cn(
312+
'hidden group-hover:flex absolute right-0 top-0 bottom-0 p-2 opacity-50 items-center',
313+
isActive || isPopoverOpen ? 'flex' : undefined
314+
)}
315+
>
316+
<CircleEllipsis size={24} />
317+
</div>
318+
</PopoverTrigger>
254319

255-
<PopoverContent className="p-2 flex flex-col overflow-hidden w-auto" portal>
256-
{isRenaming ? (
257-
<form
258-
className="w-72"
259-
onSubmit={async (e) => {
260-
e.preventDefault()
320+
<PopoverContent className="p-2 flex flex-col overflow-hidden w-auto" portal>
321+
{isRenaming ? (
322+
<form
323+
className="w-72"
324+
onSubmit={async (e) => {
325+
e.preventDefault()
261326

262-
if (e.target instanceof HTMLFormElement) {
263-
const formData = new FormData(e.target)
264-
const name = formData.get('name')
327+
if (e.target instanceof HTMLFormElement) {
328+
const formData = new FormData(e.target)
329+
const name = formData.get('name')
265330

266-
if (typeof name === 'string') {
267-
await updateDatabase({ ...database, name })
331+
if (typeof name === 'string') {
332+
await updateDatabase({ ...database, name })
333+
}
268334
}
269-
}
270335

271-
setIsPopoverOpen(false)
272-
setIsRenaming(false)
273-
}}
274-
>
275-
<input
276-
name="name"
277-
className="flex-grow w-full border-none focus-visible:ring-0 text-base bg-inherit placeholder:text-neutral-400"
278-
placeholder={`Rename ${database.name}`}
279-
defaultValue={database.name ?? undefined}
280-
autoComplete="off"
281-
autoFocus
282-
/>
283-
</form>
284-
) : (
285-
<div className="flex flex-col items-stretch w-32">
286-
<Button
287-
className="bg-inherit justify-start hover:bg-neutral-200 flex gap-3"
288-
onClick={async (e) => {
289-
e.preventDefault()
290-
setIsRenaming(true)
336+
setIsPopoverOpen(false)
337+
setIsRenaming(false)
291338
}}
292339
>
293-
<Pencil size={16} strokeWidth={2} className="flex-shrink-0" />
340+
<input
341+
name="name"
342+
className="flex-grow w-full border-none focus-visible:ring-0 text-base bg-inherit placeholder:text-neutral-400"
343+
placeholder={`Rename ${database.name}`}
344+
defaultValue={database.name ?? undefined}
345+
autoComplete="off"
346+
autoFocus
347+
/>
348+
</form>
349+
) : (
350+
<div className="flex flex-col items-stretch w-32">
351+
<Button
352+
className="bg-inherit justify-start hover:bg-neutral-200 flex gap-3"
353+
onClick={async (e) => {
354+
e.preventDefault()
355+
setIsRenaming(true)
356+
}}
357+
>
358+
<Pencil size={16} strokeWidth={2} className="flex-shrink-0" />
294359

295-
<span>Rename</span>
296-
</Button>
297-
<Button
298-
className="bg-inherit text-destructive-600 justify-start hover:bg-neutral-200 flex gap-3"
299-
onClick={async (e) => {
300-
e.preventDefault()
301-
setIsPopoverOpen(false)
302-
await deleteDatabase({ id: database.id })
360+
<span>Rename</span>
361+
</Button>
362+
<Button
363+
className="bg-inherit justify-start hover:bg-neutral-200 flex gap-3"
364+
onClick={async (e) => {
365+
e.preventDefault()
303366

304-
if (isActive) {
305-
router.push('/')
306-
}
307-
}}
308-
>
309-
<Trash2 size={16} strokeWidth={2} className="flex-shrink-0" />
367+
setIsPublishDialogOpen(true)
368+
setIsPopoverOpen(false)
369+
}}
370+
disabled={user === undefined}
371+
>
372+
<Upload size={16} strokeWidth={2} className="flex-shrink-0" />
310373

311-
<span>Delete</span>
312-
</Button>
313-
</div>
314-
)}
315-
</PopoverContent>
316-
</Popover>
317-
</Link>
374+
<span>Publish</span>
375+
</Button>
376+
<Button
377+
className="bg-inherit text-destructive-600 justify-start hover:bg-neutral-200 flex gap-3"
378+
onClick={async (e) => {
379+
e.preventDefault()
380+
setIsPopoverOpen(false)
381+
await deleteDatabase({ id: database.id })
382+
383+
if (isActive) {
384+
router.push('/')
385+
}
386+
}}
387+
>
388+
<Trash2 size={16} strokeWidth={2} className="flex-shrink-0" />
389+
390+
<span>Delete</span>
391+
</Button>
392+
</div>
393+
)}
394+
</PopoverContent>
395+
</Popover>
396+
</Link>
397+
</>
318398
)
319399
}

0 commit comments

Comments
 (0)