Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions apps/studio/components/interfaces/Linter/LinterDataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,12 @@ const LinterDataGrid = ({
{selectedLint !== null && (
<>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={30} maxSize={45} minSize={30} className="bg-studio border-t">
<ResizablePanel
defaultSize={30}
maxSize={45}
minSize={30}
className="bg-studio border-t flex flex-col h-full"
>
<div className="flex items-center justify-between w-full border-b py-3 px-6">
<div className="flex items-center gap-2">
<h3 className="text-sm m-0">
Expand All @@ -176,7 +181,7 @@ const LinterDataGrid = ({
</div>
<Button type="text" icon={<X />} onClick={handleSidepanelClose} />
</div>
<div className="p-6">
<div className="p-6 flex-grow min-h-0 overflow-y-auto">
<LintDetail lint={selectedLint} projectRef={ref!} />
</div>
</ResizablePanel>
Expand Down
24 changes: 22 additions & 2 deletions apps/studio/components/interfaces/Linter/LinterPageFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { X } from 'lucide-react'
import { LOCAL_STORAGE_KEYS } from 'common'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
import { Button, cn } from 'ui'
import { Markdown } from '../Markdown'

Expand All @@ -14,8 +17,25 @@ const LinterPageFooter = ({
refetch,
hideDbInspectCTA,
}: LinterPageFooterProps) => {
const [showBottomSection, setShowBottomSection] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.LINTER_SHOW_FOOTER,
true
)

if (!showBottomSection) {
return null
}

return (
<div className="px-6 py-6 flex gap-x-4 border-t ">
<div className="px-6 py-6 flex gap-x-4 border-t relative">
<Button
className="absolute top-1.5 right-3 px-1.5"
type="text"
size="tiny"
onClick={() => setShowBottomSection(false)}
>
<X size="14" />
</Button>
<div
className={cn(hideDbInspectCTA ? 'w-[35%]' : 'w-[33%]', 'flex flex-col gap-y-1 text-sm')}
>
Expand Down Expand Up @@ -64,4 +84,4 @@ const LinterPageFooter = ({
)
}

export default LinterPageFooter
export { LinterPageFooter }
2 changes: 1 addition & 1 deletion apps/studio/pages/project/[ref]/advisors/performance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants'
import { lintInfoMap } from 'components/interfaces/Linter/Linter.utils'
import LinterDataGrid from 'components/interfaces/Linter/LinterDataGrid'
import LinterFilters from 'components/interfaces/Linter/LinterFilters'
import LinterPageFooter from 'components/interfaces/Linter/LinterPageFooter'
import { LinterPageFooter } from 'components/interfaces/Linter/LinterPageFooter'
import AdvisorsLayout from 'components/layouts/AdvisorsLayout/AdvisorsLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { FormHeader } from 'components/ui/Forms/FormHeader'
Expand Down
2 changes: 1 addition & 1 deletion apps/studio/pages/project/[ref]/advisors/security.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants'
import { lintInfoMap } from 'components/interfaces/Linter/Linter.utils'
import LinterDataGrid from 'components/interfaces/Linter/LinterDataGrid'
import LinterFilters from 'components/interfaces/Linter/LinterFilters'
import LinterPageFooter from 'components/interfaces/Linter/LinterPageFooter'
import { LinterPageFooter } from 'components/interfaces/Linter/LinterPageFooter'
import AdvisorsLayout from 'components/layouts/AdvisorsLayout/AdvisorsLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { FormHeader } from 'components/ui/Forms/FormHeader'
Expand Down
2 changes: 2 additions & 0 deletions packages/common/constants/local-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export const LOCAL_STORAGE_KEYS = {
CLS_DIFF_WARNING: 'cls-diff-warning-dismissed',
CLS_SELECT_STAR_WARNING: 'cls-select-star-warning-dismissed',
QUERY_PERF_SHOW_BOTTOM_SECTION: 'supabase-query-perf-show-bottom-section',
LINTER_SHOW_FOOTER: 'supabase-linter-show-footer',
// Key to track account deletion requests
ACCOUNT_DELETION_REQUEST: 'supabase-account-deletion-request',
// Used for storing a user id when sending reports to Sentry. The id is hashed for anonymity.
Expand Down Expand Up @@ -110,6 +111,7 @@ const LOCAL_STORAGE_KEYS_ALLOWLIST = [
LOCAL_STORAGE_KEYS.AI_ASSISTANT_MCP_OPT_IN,
LOCAL_STORAGE_KEYS.UI_PREVIEW_REALTIME_SETTINGS,
LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0,
LOCAL_STORAGE_KEYS.LINTER_SHOW_FOOTER,
]

export function clearLocalStorage() {
Expand Down
6 changes: 3 additions & 3 deletions packages/ui-patterns/src/Banners/LW15Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ export function LW15Banner() {
<div className="relative z-10 flex items-center justify-center">
<div className="w-full flex gap-5 md:gap-10 items-center md:justify-center text-sm">
<p className="flex gap-1.5 items-center font-mono uppercase tracking-widest text-sm">
{announcement.title}
{announcement.text}
</p>
<p className="text-sm hidden sm:block">{announcement.desc}</p>
<p className="text-sm hidden sm:block">{announcement.launch}</p>
<Button size="tiny" type="default" className="px-2 !leading-none text-xs" asChild>
<Link href={announcement.link}>{announcement.button}</Link>
<Link href={announcement.link}>{announcement.cta}</Link>
</Button>
</div>
</div>
Expand Down
92 changes: 75 additions & 17 deletions packages/ui-patterns/src/Banners/SelectBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,84 @@
import React from 'react'
import Link from 'next/link'
import { Button } from 'ui/src/components/Button'
import announcement from './data.json'

export function SelectBanner() {
const selectSiteUrl = 'https://select.supabase.com/'
const desc = ['Our first user conference', 'Oct 3 2025', 'Guillermo Rauch, Dylan Field, and more']
const cta = 'Save your seat'

const baseStyles = 'flex flex-col justify-center border-l border-muted py-8 '
const textBlockStyles =
baseStyles +
'pr-8 text-xs font-mono uppercase leading-none tracking-wide text-white/50 [&_p]:mt-[5px]'

return (
<div className="relative w-full p-4 flex items-center group justify-center text-foreground-contrast dark:text-white bg-black border-b border-muted transition-colors overflow-hidden ">
<div className="relative z-10 flex items-center justify-center">
<div className="w-full flex gap-5 md:gap-10 items-center md:justify-center text-sm">
<Link target={announcement.target ?? '_self'} href={announcement.link}>
<img src="/images/select/supabase-select.svg" alt="Supabase Select" className="w-32" />
<div
className="dark relative w-full flex items-center group justify-center text-foreground-contrast bg-black border-b border-muted transition-colors overflow-hidden"
style={
{
'--line-color': 'hsl(var(--border-muted))',
'--line-width': '1px',
'--offset-from-top': '64px',
'--line-spacing': '12px', // Match -3 utility spacing used elsewhere
backgroundImage: `
/* Top horizontal line: offset from middle line by line spacing */
linear-gradient(to bottom, transparent 0, transparent calc(var(--offset-from-top) - var(--line-spacing)), var(--line-color) calc(var(--offset-from-top) - var(--line-spacing)), var(--line-color) calc(var(--offset-from-top) - var(--line-spacing) + var(--line-width)), transparent calc(var(--offset-from-top) - var(--line-spacing) + var(--line-width))),
/* Middle horizontal line */
linear-gradient(to bottom, transparent 0, transparent var(--offset-from-top), var(--line-color) var(--offset-from-top), var(--line-color) calc(var(--offset-from-top) + var(--line-width)), transparent calc(var(--offset-from-top) + var(--line-width))),
/* Bottom horizontal line: offset from middle line by line spacing */
linear-gradient(to bottom, transparent 0, transparent calc(var(--offset-from-top) + var(--line-spacing)), var(--line-color) calc(var(--offset-from-top) + var(--line-spacing)), var(--line-color) calc(var(--offset-from-top) + var(--line-spacing) + var(--line-width)), transparent calc(var(--offset-from-top) + var(--line-spacing) + var(--line-width)))
`,
backgroundSize: '100% 100%',
backgroundRepeat: 'no-repeat',
} as React.CSSProperties
}
>
<div className="relative z-10 flex gap-5 items-stretch justify-center px-3 border-l border-muted">
<div className={`${baseStyles} -px-3`}>
<Link
target="_blank"
href={selectSiteUrl}
className="transition-opacity hover:opacity-80"
>
<img src="/images/select/supabase-select.svg" alt="Supabase Select" className="w-36" />
</Link>
</div>
<div className={`${textBlockStyles} hidden md:flex`}>
<p>{desc[0]}</p>
</div>
<div className={`${textBlockStyles} hidden sm:flex`}>
<p>{desc[1]}</p>
</div>
<div className={`${textBlockStyles} hidden xl:flex`}>
<p>{desc[2]}</p>
</div>

<p className="text-sm hidden sm:block">
{announcement.desc}
<span className="hidden xl:inline">{announcement.verbose}</span>
</p>

<Button size="tiny" type="default" className="px-2 !leading-none text-xs" asChild>
<Link target={announcement.target ?? '_self'} href={announcement.link}>
{announcement.button}
</Link>
</Button>
<div className="flex flex-col justify-center -px-4 border-x border-muted border-dashed relative after:absolute after:top-0 after:left-full after:w-screen after:h-full after:bg-black after:-z-10">
<Link
target="_blank"
href={selectSiteUrl}
className="relative before:absolute before:inset-0 before:bg-black before:-z-10 px-4 py-1 h-10 flex items-center justify-center bg-brand-600/20 hover:bg-brand-600/50 outline-1 outline-dashed outline-brand-600/40 hover:outline-brand-600 text-sm text-white font-medium transition-all duration-200"
>
{cta}
{/* Crosshairs */}
<div className="absolute pointer-events-none inset-0 z-10">
{['top-left', 'top-right', 'bottom-left', 'bottom-right'].map((position) => (
<div
key={position}
className={`absolute ${position === 'top-left' ? 'top-0 left-0' : position === 'top-right' ? 'top-0 right-0' : position === 'bottom-left' ? 'bottom-0 left-0' : 'bottom-0 right-0'}`}
>
<div
className={`absolute ${position.includes('left') ? '-left-px' : '-right-px'} ${position.includes('top') ? '-top-[3px]' : '-bottom-[3px]'} w-px h-[5px]`}
style={{ backgroundColor: 'hsl(var(--brand-600))' }}
/>
<div
className={`absolute ${position.includes('left') ? '-left-[3px]' : '-right-[3px]'} ${position.includes('top') ? '-top-px' : '-bottom-px'} w-[5px] h-px`}
style={{ backgroundColor: 'hsl(var(--brand-600))' }}
/>
</div>
))}
</div>
</Link>
</div>
</div>
</div>
Expand Down
11 changes: 5 additions & 6 deletions packages/ui-patterns/src/Banners/data.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"title": "Supabase Select",
"desc": "Our first user conference · October 3, San Francisco",
"verbose": " · Guillermo Rauch, Dylan Field, and more",
"link": "https://select.supabase.com/",
"target": "_blank",
"button": "Save your seat"
"text": "",
"launch": "",
"launchDate": "2025-07-17T08:00:00.000-07:00",
"link": "#",
"cta": "Learn more"
}
2 changes: 1 addition & 1 deletion packages/ui-patterns/src/PromoToast/PromoToast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const PromoToast = () => {
poster={`${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/images/launch-week/lw15/assets/lw15-galaxy.png`}
/>
<div className="relative z-10 text-foreground-lighter uppercase flex flex-col text-sm w-full mb-2">
<span className="mb-1">{announcement.title}</span>
<span className="mb-1">{announcement.text}</span>
<p className="relative z-10 text-foreground flex flex-col text-xl w-full leading-7"></p>
</div>

Expand Down
6 changes: 3 additions & 3 deletions packages/ui/src/layout/banners/Announcement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { X } from 'lucide-react'

export interface AnnouncementProps {
show: boolean
title: string
launchDate: string | null
text: string
launchDate: string
link: string
badge?: string
}
Expand Down Expand Up @@ -66,7 +66,7 @@ const Announcement = ({
<div className={cn('relative z-40 w-full', className)}>
{dismissable && !isLaunchWeekSection && (
<div
className="absolute z-50 right-4 flex h-full items-center opacity-100 text-foreground-contrast dark:text-foreground transition-opacity hover:opacity-100 hover:cursor-pointer"
className="absolute z-50 right-4 flex h-full items-center opacity-100 text-foreground-contrast dark:text-foreground transition-opacity hover:opacity-80 hover:cursor-pointer"
onClick={handleClose}
>
<X size={16} />
Expand Down
Loading