From 141c27cda7b8aed155b9c9b793c531bd56f3b8e9 Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Mon, 18 Sep 2023 19:30:22 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20autofocus=20for=20searchbar?= =?UTF-8?q?=20(#1408)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 1 + public/locales/en/user/preferences.json | 4 ++++ .../User/Preferences/SearchEngineSelector.tsx | 5 +++++ .../layout/Templates/BoardLayout.tsx | 7 ++++++- src/components/layout/Templates/MainLayout.tsx | 18 ++++++++++++++++-- src/components/layout/header/Header.tsx | 4 +++- src/components/layout/header/Search.tsx | 4 +++- src/pages/user/preferences.tsx | 1 + src/server/api/routers/user.ts | 1 + src/server/auth.ts | 6 ++++++ src/validations/user.ts | 1 + 11 files changed, 47 insertions(+), 5 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 63ea23a40..b94360604 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -86,6 +86,7 @@ model UserSettings { disablePingPulse Boolean @default(false) replacePingWithIcons Boolean @default(false) useDebugLanguage Boolean @default(false) + autoFocusSearch Boolean @default(false) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId]) diff --git a/public/locales/en/user/preferences.json b/public/locales/en/user/preferences.json index 069cd7065..d1bbf2171 100644 --- a/public/locales/en/user/preferences.json +++ b/public/locales/en/user/preferences.json @@ -36,6 +36,10 @@ "newTab": { "label": "Open search results in a new tab" }, + "autoFocus": { + "label": "Focus search bar on page load.", + "description": "This will automatically focus the search bar, when you navigate to the board pages. It will only work on desktop devices." + }, "template": { "label": "Query URL", "description": "Use %s as a placeholder for the query" diff --git a/src/components/User/Preferences/SearchEngineSelector.tsx b/src/components/User/Preferences/SearchEngineSelector.tsx index 6c34f4fa0..d8e301ca2 100644 --- a/src/components/User/Preferences/SearchEngineSelector.tsx +++ b/src/components/User/Preferences/SearchEngineSelector.tsx @@ -31,6 +31,11 @@ export const SearchEngineSettings = () => { label={t('searchEngine.newTab.label')} {...form.getInputProps('openSearchInNewTab', { type: 'checkbox' })} /> + { const { config } = useConfigContext(); + const { data: session } = useSession(); return ( - }> + } + > {children} diff --git a/src/components/layout/Templates/MainLayout.tsx b/src/components/layout/Templates/MainLayout.tsx index 4a648650c..af3c8bbad 100644 --- a/src/components/layout/Templates/MainLayout.tsx +++ b/src/components/layout/Templates/MainLayout.tsx @@ -6,9 +6,16 @@ type MainLayoutProps = { headerActions?: React.ReactNode; contentComponents?: React.ReactNode; children: React.ReactNode; + autoFocusSearch?: boolean; }; -export const MainLayout = ({ showExperimental, headerActions, contentComponents, children }: MainLayoutProps) => { +export const MainLayout = ({ + showExperimental, + headerActions, + contentComponents, + children, + autoFocusSearch, +}: MainLayoutProps) => { const theme = useMantineTheme(); return ( @@ -18,7 +25,14 @@ export const MainLayout = ({ showExperimental, headerActions, contentComponents, background: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[1], }, }} - header={} + header={ + + } className="dashboard-app-shell" > {children} diff --git a/src/components/layout/header/Header.tsx b/src/components/layout/header/Header.tsx index 5ecd9256f..0bc301db7 100644 --- a/src/components/layout/header/Header.tsx +++ b/src/components/layout/header/Header.tsx @@ -23,6 +23,7 @@ type MainHeaderProps = { headerActions?: React.ReactNode; contentComponents?: React.ReactNode; leftIcon?: React.ReactNode; + autoFocusSearch?: boolean; }; export const MainHeader = ({ @@ -31,6 +32,7 @@ export const MainHeader = ({ headerActions, leftIcon, contentComponents, + autoFocusSearch, }: MainHeaderProps) => { const { breakpoints } = useMantineTheme(); const isSmallerThanMd = useMediaQuery(`(max-width: ${breakpoints.sm})`); @@ -51,7 +53,7 @@ export const MainHeader = ({ - {!isSmallerThanMd && } + {!isSmallerThanMd && } diff --git a/src/components/layout/header/Search.tsx b/src/components/layout/header/Search.tsx index d4e2d73fd..e0de950b2 100644 --- a/src/components/layout/header/Search.tsx +++ b/src/components/layout/header/Search.tsx @@ -19,9 +19,10 @@ import { MovieModal } from './Search/MovieModal'; type SearchProps = { isMobile?: boolean; + autoFocus?: boolean; }; -export const Search = ({ isMobile }: SearchProps) => { +export const Search = ({ isMobile, autoFocus }: SearchProps) => { const { t } = useTranslation('layout/header'); const [search, setSearch] = useState(''); const ref = useRef(null); @@ -62,6 +63,7 @@ export const Search = ({ isMobile }: SearchProps) => { variant="filled" placeholder={`${t('search.label')}...`} hoverOnSearchChange + autoFocus={autoFocus} rightSection={ ref.current?.focus()} diff --git a/src/pages/user/preferences.tsx b/src/pages/user/preferences.tsx index c6a12e897..2dcef24e0 100644 --- a/src/pages/user/preferences.tsx +++ b/src/pages/user/preferences.tsx @@ -89,6 +89,7 @@ const SettingsComponent = ({ replaceDotsWithIcons: settings.replacePingWithIcons, searchTemplate: settings.searchTemplate, openSearchInNewTab: settings.openSearchInNewTab, + autoFocusSearch: settings.autoFocusSearch, }, validate: i18nZodResolver(updateSettingsValidationSchema), validateInputOnBlur: true, diff --git a/src/server/api/routers/user.ts b/src/server/api/routers/user.ts index 6b8db0a3f..1287d1d95 100644 --- a/src/server/api/routers/user.ts +++ b/src/server/api/routers/user.ts @@ -221,6 +221,7 @@ export const userRouter = createTRPCRouter({ firstDayOfWeek: input.firstDayOfWeek, searchTemplate: input.searchTemplate, openSearchInNewTab: input.openSearchInNewTab, + autoFocusSearch: input.autoFocusSearch, }, }, }, diff --git a/src/server/auth.ts b/src/server/auth.ts index 70ba1f873..770af0f10 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -24,6 +24,7 @@ declare module 'next-auth' { id: string; isAdmin: boolean; colorScheme: 'light' | 'dark' | 'environment'; + autoFocusSearch: boolean; language: string; // ...other properties // role: UserRole; @@ -33,6 +34,7 @@ declare module 'next-auth' { interface User { isAdmin: boolean; colorScheme: 'light' | 'dark' | 'environment'; + autoFocusSearch: boolean; language: string; // ...other properties // role: UserRole; @@ -75,6 +77,7 @@ export const constructAuthOptions = ( select: { colorScheme: true, language: true, + autoFocusSearch: true, }, }, }, @@ -83,6 +86,7 @@ export const constructAuthOptions = ( session.user.isAdmin = userFromDatabase.isAdmin; session.user.colorScheme = colorSchemeParser.parse(userFromDatabase.settings?.colorScheme); session.user.language = userFromDatabase.settings?.language ?? 'en'; + session.user.autoFocusSearch = userFromDatabase.settings?.autoFocusSearch ?? false; } return session; @@ -148,6 +152,7 @@ export const constructAuthOptions = ( select: { colorScheme: true, language: true, + autoFocusSearch: true, }, }, }, @@ -173,6 +178,7 @@ export const constructAuthOptions = ( isAdmin: false, colorScheme: colorSchemeParser.parse(user.settings?.colorScheme), language: user.settings?.language ?? 'en', + autoFocusSearch: user.settings?.autoFocusSearch ?? false, }; }, }), diff --git a/src/validations/user.ts b/src/validations/user.ts index c44679a49..c88bcc99a 100644 --- a/src/validations/user.ts +++ b/src/validations/user.ts @@ -49,4 +49,5 @@ export const updateSettingsValidationSchema = z.object({ replaceDotsWithIcons: z.boolean(), searchTemplate: z.string().nonempty().max(256), openSearchInNewTab: z.boolean(), + autoFocusSearch: z.boolean(), });