Kaynağa Gözat

Merge pull request #29292 from overleaf/dp-dashboard-theme-toggle

Add theme toggle to project dashboard

GitOrigin-RevId: 4c76bcc36f77d7fd883798f8ccfcb5d1cf1a54b0
David 9 ay önce
ebeveyn
işleme
38edeca871

+ 1 - 0
services/web/app/views/project/list-react.pug

@@ -34,6 +34,7 @@ block append meta
 	meta(name='ol-tags' data-type='json' content=tags)
 	meta(name='ol-portalTemplates' data-type='json' content=portalTemplates)
 	meta(name='ol-userSettings' data-type='json' content=userSettings)
+	meta(name='ol-overallThemes' data-type='json' content=overallThemes)
 	meta(
 		name='ol-prefetchedProjectsBlob'
 		data-type='json'

+ 1 - 0
services/web/frontend/extracted-translations.json

@@ -1857,6 +1857,7 @@
   "the_visual_editor_cant_preview_this_type_of_image_file": "",
   "the_width_you_choose_here_is_based_on_the_width_of_the_text_in_your_document": "",
   "their_projects_will_be_transferred_to_another_user": "",
+  "theme": "",
   "then_x_price_per_month": "",
   "then_x_price_per_year": "",
   "there_are_lots_of_options_to_edit_and_customize_your_figures": "",

+ 4 - 0
services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx

@@ -17,6 +17,7 @@ import { AccountMenuItems } from '@/shared/components/navbar/account-menu-items'
 import { useScrolled } from '@/features/project-list/components/sidebar/use-scroll'
 import { useSendProjectListMB } from '@/features/project-list/components/project-list-events'
 import { SurveyWidgetDsNav } from '@/features/project-list/components/survey-widget-ds-nav'
+import { useFeatureFlag } from '@/shared/context/split-test-context'
 
 function SidebarDsNav() {
   const { t } = useTranslation()
@@ -36,6 +37,8 @@ function SidebarDsNav() {
     item => item.text === 'help_and_resources'
   ) as NavbarDropdownItemData
   const { containerRef, scrolledUp, scrolledDown } = useScrolled()
+  const themedDsNav = useFeatureFlag('themed-project-dashboard')
+
   return (
     <div
       className="project-list-sidebar-wrapper-react d-none d-md-flex"
@@ -159,6 +162,7 @@ function SidebarDsNav() {
                   <AccountMenuItems
                     sessionUser={sessionUser}
                     showSubscriptionLink={showSubscriptionLink}
+                    showThemeToggle={themedDsNav}
                   />
                 </Dropdown.Menu>
               </Dropdown>

+ 55 - 0
services/web/frontend/js/features/project-list/components/sidebar/theme-toggle.tsx

@@ -0,0 +1,55 @@
+import useSetOverallTheme from '@/features/editor-left-menu/hooks/use-set-overall-theme'
+import MaterialIcon from '@/shared/components/material-icon'
+import OLTooltip from '@/shared/components/ol/ol-tooltip'
+import { useUserSettingsContext } from '@/shared/context/user-settings-context'
+import getMeta from '@/utils/meta'
+import { OverallThemeMeta } from '@ol-types/project-settings'
+import { useTranslation } from 'react-i18next'
+
+const getIcon = (theme: OverallThemeMeta) => {
+  switch (theme.val) {
+    case 'light-':
+      return 'light_mode'
+    case 'system':
+      return 'computer'
+    default:
+      return 'dark_mode'
+  }
+}
+
+export default function ThemeToggle() {
+  const {
+    userSettings: { overallTheme },
+  } = useUserSettingsContext()
+  const setOverallTheme = useSetOverallTheme()
+  const overallThemes = getMeta('ol-overallThemes')
+  const { t } = useTranslation()
+
+  return (
+    <fieldset className="dropdown-item theme-toggle">
+      <legend>{t('theme')}</legend>
+      <div className="theme-toggle-radios">
+        {overallThemes.map(theme => (
+          <OLTooltip
+            key={theme.val}
+            description={theme.name}
+            id={`theme-switch-${theme.name}-tooltip`}
+          >
+            <div className="theme-toggle-radio">
+              <input
+                id={`theme-switch-${theme.name}`}
+                type="radio"
+                value={theme.val}
+                checked={overallTheme === theme.val}
+                onChange={() => setOverallTheme(theme.val)}
+              />
+              <label htmlFor={`theme-switch-${theme.name}`}>
+                <MaterialIcon type={getIcon(theme)} />
+              </label>
+            </div>
+          </OLTooltip>
+        ))}
+      </div>
+    </fieldset>
+  )
+}

+ 10 - 0
services/web/frontend/js/shared/components/navbar/account-menu-items.tsx

@@ -7,17 +7,21 @@ import NavDropdownDivider from './nav-dropdown-divider'
 import NavDropdownLinkItem from './nav-dropdown-link-item'
 import { useDsNavStyle } from '@/features/project-list/components/use-is-ds-nav'
 import { SignOut } from '@phosphor-icons/react'
+import ThemeToggle from '@/features/project-list/components/sidebar/theme-toggle'
 
 export function AccountMenuItems({
   sessionUser,
   showSubscriptionLink,
+  showThemeToggle = false,
 }: {
   sessionUser: NavbarSessionUser
   showSubscriptionLink: boolean
+  showThemeToggle?: boolean
 }) {
   const { t } = useTranslation()
   const logOutFormId = 'logOutForm'
   const dsNavStyle = useDsNavStyle()
+
   return (
     <>
       <Dropdown.Item as="li" disabled role="menuitem">
@@ -32,6 +36,12 @@ export function AccountMenuItems({
           {t('subscription')}
         </NavDropdownLinkItem>
       ) : null}
+      {showThemeToggle && (
+        <DropdownListItem>
+          <ThemeToggle />
+        </DropdownListItem>
+      )}
+
       <NavDropdownDivider />
       <DropdownListItem>
         {

+ 59 - 0
services/web/frontend/stylesheets/pages/project-list-ds-nav.scss

@@ -337,3 +337,62 @@
     }
   }
 }
+
+.theme-toggle {
+  display: flex;
+  justify-content: space-between;
+  cursor: default !important;
+  align-items: center;
+
+  &:hover {
+    background-color: transparent !important;
+    color: var(--content-primary-themed);
+  }
+
+  legend {
+    font-size: var(--font-size-02);
+    line-height: var(--line-height-02);
+    margin-bottom: 0;
+  }
+}
+
+.theme-toggle-radios {
+  display: flex;
+  border-radius: var(--border-radius-full);
+  background-color: var(--bg-secondary-themed);
+  padding: var(--spacing-01);
+  gap: var(--spacing-01);
+}
+
+:root {
+  --theme-toggle-selected-background: var(--green-70);
+}
+
+@include theme('light') {
+  --theme-toggle-selected-background: var(--green-20);
+}
+
+.theme-toggle-radio {
+  display: flex;
+
+  input {
+    all: unset;
+  }
+
+  label {
+    display: flex;
+    padding: var(--spacing-03);
+    margin-bottom: 0;
+    border-radius: var(--border-radius-full);
+    cursor: pointer;
+    color: var(--content-primary-themed);
+  }
+
+  .material-symbols {
+    font-size: var(--font-size-03);
+  }
+
+  input:checked + label {
+    background-color: var(--theme-toggle-selected-background);
+  }
+}