diff --git a/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx b/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx index a7e9c29e8a9d3..ae9bcad47b1d4 100644 --- a/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx +++ b/apps/studio/components/interfaces/Linter/LinterDataGrid.tsx @@ -166,7 +166,12 @@ const LinterDataGrid = ({ {selectedLint !== null && ( <> - +

@@ -176,7 +181,7 @@ const LinterDataGrid = ({

-
+
diff --git a/apps/studio/components/interfaces/Linter/LinterPageFooter.tsx b/apps/studio/components/interfaces/Linter/LinterPageFooter.tsx index 65a072ac9ed0e..76bb8b6a3d102 100644 --- a/apps/studio/components/interfaces/Linter/LinterPageFooter.tsx +++ b/apps/studio/components/interfaces/Linter/LinterPageFooter.tsx @@ -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' @@ -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 ( -
+
+
@@ -64,4 +84,4 @@ const LinterPageFooter = ({ ) } -export default LinterPageFooter +export { LinterPageFooter } diff --git a/apps/studio/pages/project/[ref]/advisors/performance.tsx b/apps/studio/pages/project/[ref]/advisors/performance.tsx index ff4321175aa58..3b0e83b7a2320 100644 --- a/apps/studio/pages/project/[ref]/advisors/performance.tsx +++ b/apps/studio/pages/project/[ref]/advisors/performance.tsx @@ -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' diff --git a/apps/studio/pages/project/[ref]/advisors/security.tsx b/apps/studio/pages/project/[ref]/advisors/security.tsx index cd324bed41ffb..aaa28234f92f2 100644 --- a/apps/studio/pages/project/[ref]/advisors/security.tsx +++ b/apps/studio/pages/project/[ref]/advisors/security.tsx @@ -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' diff --git a/packages/common/constants/local-storage.ts b/packages/common/constants/local-storage.ts index 3572600e27315..03d597f036654 100644 --- a/packages/common/constants/local-storage.ts +++ b/packages/common/constants/local-storage.ts @@ -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. @@ -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() { diff --git a/packages/ui-patterns/src/Banners/LW15Banner.tsx b/packages/ui-patterns/src/Banners/LW15Banner.tsx index 84268c24c4449..8e87d463ebb33 100644 --- a/packages/ui-patterns/src/Banners/LW15Banner.tsx +++ b/packages/ui-patterns/src/Banners/LW15Banner.tsx @@ -53,11 +53,11 @@ export function LW15Banner() {

- {announcement.title} + {announcement.text}

-

{announcement.desc}

+

{announcement.launch}

diff --git a/packages/ui-patterns/src/Banners/SelectBanner.tsx b/packages/ui-patterns/src/Banners/SelectBanner.tsx index 32afcf91928bf..b3cae094a4bd6 100644 --- a/packages/ui-patterns/src/Banners/SelectBanner.tsx +++ b/packages/ui-patterns/src/Banners/SelectBanner.tsx @@ -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 ( -
-
-
- - Supabase Select +
+
+
+ + Supabase Select +
+ + + -

- {announcement.desc} - {announcement.verbose} -

- - +
+ + {cta} + {/* Crosshairs */} +
+ {['top-left', 'top-right', 'bottom-left', 'bottom-right'].map((position) => ( +
+
+
+
+ ))} +
+
diff --git a/packages/ui-patterns/src/Banners/data.json b/packages/ui-patterns/src/Banners/data.json index bd3f41eb0f4ea..a7f1e2fee1432 100644 --- a/packages/ui-patterns/src/Banners/data.json +++ b/packages/ui-patterns/src/Banners/data.json @@ -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" } diff --git a/packages/ui-patterns/src/PromoToast/PromoToast.tsx b/packages/ui-patterns/src/PromoToast/PromoToast.tsx index 6c7c49049d277..af51c5e351544 100644 --- a/packages/ui-patterns/src/PromoToast/PromoToast.tsx +++ b/packages/ui-patterns/src/PromoToast/PromoToast.tsx @@ -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`} />
- {announcement.title} + {announcement.text}

diff --git a/packages/ui/src/layout/banners/Announcement.tsx b/packages/ui/src/layout/banners/Announcement.tsx index 60dc358c34a44..aef0cde8e3ef7 100644 --- a/packages/ui/src/layout/banners/Announcement.tsx +++ b/packages/ui/src/layout/banners/Announcement.tsx @@ -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 } @@ -66,7 +66,7 @@ const Announcement = ({
{dismissable && !isLaunchWeekSection && (