Просмотр исходного кода

Merge pull request #31950 from overleaf/mj-themed-project-load

[web] Add themed project loading screen

GitOrigin-RevId: b73d8c825b5ab04ede1c9dde10a6891be63758a4
Mathias Jakobsen 5 месяцев назад
Родитель
Сommit
ada0922988

+ 18 - 0
services/web/app/src/Features/Project/ProjectController.mjs

@@ -880,6 +880,10 @@ const _ProjectController = {
         user
       )
 
+      const initialLoadingScreenTheme = getInitialLoadingScreenTheme(
+        userSettings?.overallTheme
+      )
+
       res.render(template, {
         title: project.name,
         priority_title: true,
@@ -916,6 +920,7 @@ const _ProjectController = {
           isMemberOfGroupSubscription: userIsMemberOfGroupSubscription,
           hasInstitutionLicence: userHasInstitutionLicence,
         },
+        initialLoadingScreenTheme,
         userSettings,
         labsExperiments: user.labsExperiments ?? [],
         privilegeLevel,
@@ -1275,6 +1280,19 @@ const _ProjectController = {
   },
 }
 
+function getInitialLoadingScreenTheme(overallThemeSetting) {
+  switch (overallThemeSetting) {
+    case 'light-':
+      return 'light'
+    case '':
+      return 'dark'
+    case 'system':
+      return 'system'
+    default:
+      return 'dark'
+  }
+}
+
 const defaultSettingsForAnonymousUser = userId => ({
   id: userId,
   ace: {

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

@@ -14,7 +14,7 @@ block entrypointVar
 block content
 	//- TODO: remove `main` once it's no longer needed by browser extensions
 	main#ide-root
-		.loading-screen
+		div(class=['loading-screen', `loading-screen-init-${initialLoadingScreenTheme}`])
 			.loading-screen-brand-container
 				.loading-screen-brand(style='height: 20%')
 			h3.loading-screen-label #{translate("loading")}

+ 2 - 1
services/web/frontend/js/features/ide-react/components/loading.tsx

@@ -5,6 +5,7 @@ import getMeta from '@/utils/meta'
 import { useConnectionContext } from '../context/connection-context'
 import { useIdeReactContext } from '@/features/ide-react/context/ide-react-context'
 import { LoadingError, LoadingErrorProps } from './loading-error'
+import useThemedPage from '@/shared/hooks/use-themed-page'
 
 type Part = 'initial' | 'render' | 'connection' | 'translations' | 'project'
 
@@ -22,7 +23,7 @@ export const Loading: FC<{
   setLoaded: (value: boolean) => void
 }> = ({ setLoaded }) => {
   const [loadedParts, setLoadedParts] = useState(initialParts)
-
+  useThemedPage()
   const progress = (loadedParts.size / totalParts.size) * 100
 
   useEffect(() => {

+ 15 - 18
services/web/frontend/js/features/token-access/components/token-access-root.tsx

@@ -111,28 +111,25 @@ function TokenAccessRoot() {
   }
 
   return (
-    <div>
-      <div>
-        <a
-          href="/project"
-          // TODO: class name
-          style={{ fontSize: '2rem', marginLeft: '1rem', color: '#ddd' }}
-        >
+    <div className="token-access-container">
+      <div className="token-access-action-header">
+        <a href="/project" className="token-access-home-link">
           <MaterialIcon type="arrow_left_alt" style={{ fontSize: 'inherit' }} />
         </a>
       </div>
+      <div className="token-access-content">
+        {mode === 'access-attempt' && (
+          <AccessAttemptScreen
+            accessError={accessError}
+            inflight={inflight}
+            loadingScreenBrandHeight={loadingScreenBrandHeight}
+          />
+        )}
 
-      {mode === 'access-attempt' && (
-        <AccessAttemptScreen
-          accessError={accessError}
-          inflight={inflight}
-          loadingScreenBrandHeight={loadingScreenBrandHeight}
-        />
-      )}
-
-      {V1ImportDataScreen && mode === 'v1Import' && v1ImportData && (
-        <V1ImportDataScreen v1ImportData={v1ImportData} />
-      )}
+        {V1ImportDataScreen && mode === 'v1Import' && v1ImportData && (
+          <V1ImportDataScreen v1ImportData={v1ImportData} />
+        )}
+      </div>
     </div>
   )
 }

+ 2 - 2
services/web/frontend/js/shared/hooks/use-themed-page.tsx

@@ -1,10 +1,10 @@
-import { useEffect } from 'react'
+import { useLayoutEffect } from 'react'
 import { useActiveOverallTheme } from './use-active-overall-theme'
 
 export default function useThemedPage(featureFlag?: string) {
   const activeOverallTheme = useActiveOverallTheme(featureFlag)
 
-  useEffect(() => {
+  useLayoutEffect(() => {
     // Sets the body's data-theme attribute for theming
     document.body.dataset.theme =
       activeOverallTheme === 'dark' ? 'default' : 'light'

+ 1 - 0
services/web/frontend/stylesheets/pages/all.scss

@@ -57,3 +57,4 @@
 @import 'wiki';
 @import 'templates';
 @import 'notification-settings';
+@import 'token-access';

+ 45 - 7
services/web/frontend/stylesheets/pages/editor/loading-screen.scss

@@ -1,5 +1,45 @@
 @use 'sass:math';
 
+@mixin loading-screen-dark {
+  --loading-screen-ol-logo-empty-url: url(../../../../public/img/ol-brand/overleaf-o-grey.svg);
+  --loading-screen-ol-logo-full-url: url(../../../../public/img/ol-brand/overleaf-o-white.svg);
+  --loading-screen-bg-color: var(--bg-dark-primary);
+  --loading-screen-color: var(--content-secondary-dark);
+  --loading-screen-danger-color: var(--content-danger-dark);
+}
+
+@mixin loading-screen-light {
+  --loading-screen-ol-logo-empty-url: url(../../../../public/img/ol-brand/overleaf-o-grey.svg);
+  --loading-screen-ol-logo-full-url: url(../../../../public/img/ol-brand/overleaf-o.svg);
+  --loading-screen-bg-color: var(--bg-light-primary);
+  --loading-screen-color: var(--content-secondary);
+  --loading-screen-danger-color: var(--content-danger);
+}
+
+:root {
+  @include loading-screen-light;
+
+  @include theme('default') {
+    @include loading-screen-dark;
+  }
+
+  .loading-screen-init-system {
+    @include loading-screen-light;
+
+    @media (prefers-color-scheme: dark) {
+      @include loading-screen-dark;
+    }
+  }
+
+  .loading-screen-init-light {
+    @include loading-screen-light;
+  }
+
+  .loading-screen-init-dark {
+    @include loading-screen-dark;
+  }
+}
+
 @keyframes blink {
   0% {
     opacity: 0.2;
@@ -21,7 +61,7 @@
   align-items: center;
   width: 100%;
   height: 100%;
-  background-color: #fff;
+  background-color: var(--loading-screen-bg-color);
 
   .loading-screen-brand-container {
     min-width: 200px;
@@ -31,8 +71,7 @@
     position: relative;
     padding-top: math.percentage(math.div(150, 130)); // dimensions of the SVG
     height: 0;
-    background: url(../../../../public/img/ol-brand/overleaf-o-grey.svg)
-      no-repeat bottom / 100%;
+    background: var(--loading-screen-ol-logo-empty-url) no-repeat bottom / 100%;
 
     &::after {
       content: '';
@@ -41,8 +80,7 @@
       right: 0;
       bottom: 0;
       left: 0;
-      background: url(../../../../public/img/ol-brand/overleaf-o.svg) no-repeat
-        bottom / 100%;
+      background: var(--loading-screen-ol-logo-full-url) no-repeat bottom / 100%;
       transition: height 0.5s;
     }
   }
@@ -52,7 +90,7 @@
     padding-top: var(--spacing-09);
     font-family: $font-family-serif;
     font-size: var(--font-size-07);
-    color: var(--content-secondary);
+    color: var(--loading-screen-color);
   }
 
   .loading-screen-ellip {
@@ -70,6 +108,6 @@
   .loading-screen-error {
     margin: 0;
     padding-top: var(--spacing-06);
-    color: var(--content-danger);
+    color: var(--loading-screen-danger-color);
   }
 }

+ 37 - 0
services/web/frontend/stylesheets/pages/token-access.scss

@@ -0,0 +1,37 @@
+#token-access-page {
+  height: 100vh;
+  height: 100dvh;
+}
+
+@include theme('default') {
+  .token-access-content {
+    @include dark-bg;
+  }
+}
+
+.token-access-container {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+}
+
+.token-access-action-header {
+  background-color: var(--bg-primary-themed);
+  flex: 0 0 auto;
+}
+
+.token-access-content {
+  flex: 1 1 auto;
+  color: var(--content-primary-themed);
+
+  h1,
+  h2 {
+    color: var(--content-primary-themed);
+  }
+}
+
+.token-access-home-link {
+  font-size: 2rem;
+  margin-left: 1rem;
+  color: var(--content-primary-themed);
+}