mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(console): display topbar shadow while scrolling (#1340)
This commit is contained in:
parent
67a87bb651
commit
b3774cd43a
5 changed files with 55 additions and 6 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -31,6 +31,7 @@
|
||||||
"pnpm",
|
"pnpm",
|
||||||
"silverhand",
|
"silverhand",
|
||||||
"slonik",
|
"slonik",
|
||||||
"stylelint"
|
"stylelint",
|
||||||
|
"topbar"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
@ -8,11 +9,15 @@ import GetStartedProgress from '@/pages/GetStarted/components/GetStartedProgress
|
||||||
import UserInfo from '../UserInfo';
|
import UserInfo from '../UserInfo';
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
|
||||||
const Topbar = () => {
|
type Props = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Topbar = ({ className }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.topbar}>
|
<div className={classNames(styles.topbar, className)}>
|
||||||
<Logo className={styles.logo} />
|
<Logo className={styles.logo} />
|
||||||
<div className={styles.line} />
|
<div className={styles.line} />
|
||||||
<div className={styles.text}>{t('admin_console.title')}</div>
|
<div className={styles.text}>{t('admin_console.title')}</div>
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topbarShadow {
|
||||||
|
box-shadow: var(--shadow-2);
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { LogtoClientError, useLogto } from '@logto/react';
|
import { LogtoClientError, useLogto } from '@logto/react';
|
||||||
import React, { useEffect } from 'react';
|
import { conditional } from '@silverhand/essentials';
|
||||||
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { Outlet, useHref, useLocation, useNavigate } from 'react-router-dom';
|
import { Outlet, useHref, useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import AppError from '@/components/AppError';
|
import AppError from '@/components/AppError';
|
||||||
import AppLoading from '@/components/AppLoading';
|
import AppLoading from '@/components/AppLoading';
|
||||||
import SessionExpired from '@/components/SessionExpired';
|
import SessionExpired from '@/components/SessionExpired';
|
||||||
|
import useScroll from '@/hooks/use-scroll';
|
||||||
import useSettings from '@/hooks/use-settings';
|
import useSettings from '@/hooks/use-settings';
|
||||||
import useUserPreferences from '@/hooks/use-user-preferences';
|
import useUserPreferences from '@/hooks/use-user-preferences';
|
||||||
|
|
||||||
|
@ -23,6 +25,8 @@ const AppContent = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { firstItem } = useSidebarMenuItems();
|
const { firstItem } = useSidebarMenuItems();
|
||||||
|
const mainRef = useRef<HTMLDivElement>(null);
|
||||||
|
const { scrollTop } = useScroll(mainRef.current);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isAuthenticated) {
|
if (!isAuthenticated) {
|
||||||
|
@ -51,10 +55,10 @@ const AppContent = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.app}>
|
<div className={styles.app}>
|
||||||
<Topbar />
|
<Topbar className={conditional(scrollTop && styles.topbarShadow)} />
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<div className={styles.main}>
|
<div ref={mainRef} className={styles.main}>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
35
packages/console/src/hooks/use-scroll.ts
Normal file
35
packages/console/src/hooks/use-scroll.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import { Nullable } from '@silverhand/essentials';
|
||||||
|
import { useState, useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
|
const useScroll = (contentRef: Nullable<HTMLDivElement>) => {
|
||||||
|
const [scrollTop, setScrollTop] = useState(0);
|
||||||
|
const [scrollLeft, setScrollLeft] = useState(0);
|
||||||
|
|
||||||
|
const handleScroll = useCallback(() => {
|
||||||
|
if (!contentRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { scrollTop, scrollLeft } = contentRef;
|
||||||
|
setScrollTop(scrollTop);
|
||||||
|
setScrollLeft(scrollLeft);
|
||||||
|
}, [contentRef]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!contentRef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
contentRef.addEventListener('scroll', handleScroll);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
contentRef.removeEventListener('scroll', handleScroll);
|
||||||
|
};
|
||||||
|
}, [handleScroll, contentRef]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
scrollTop,
|
||||||
|
scrollLeft,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useScroll;
|
Loading…
Reference in a new issue