From 095edfd49ff3640c6471b5e5242fc0f1e4dddf35 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Fri, 2 Feb 2024 01:38:58 -0800 Subject: [PATCH] Add custom spoiler component --- src/renderer/components/spoiler/index.tsx | 62 +++++++++---------- .../components/spoiler/spoiler.module.scss | 32 ++++++++-- src/renderer/hooks/index.ts | 1 + src/renderer/hooks/use-is-overflow.ts | 20 ++++++ 4 files changed, 78 insertions(+), 37 deletions(-) create mode 100644 src/renderer/hooks/use-is-overflow.ts diff --git a/src/renderer/components/spoiler/index.tsx b/src/renderer/components/spoiler/index.tsx index ef7a5d2d..9e015ae5 100644 --- a/src/renderer/components/spoiler/index.tsx +++ b/src/renderer/components/spoiler/index.tsx @@ -1,41 +1,39 @@ -import { ReactNode } from 'react'; -import { Spoiler as MantineSpoiler } from '@mantine/core'; -import { useTranslation } from 'react-i18next'; +import clsx from 'clsx'; +import { HTMLAttributes, ReactNode, useRef, useState } from 'react'; import styles from './spoiler.module.scss'; +import { useIsOverflow } from '/@/renderer/hooks'; -type SpoilerProps = { - children: ReactNode; - hideLabel?: boolean; - initialState?: boolean; - maxHeight: number; - showLabel?: ReactNode; - transitionDuration?: number; -}; +interface SpoilerProps extends HTMLAttributes { + children?: ReactNode; + defaultOpened?: boolean; + maxHeight?: number; +} -export const Spoiler = ({ - hideLabel, - initialState, - maxHeight, - showLabel, - transitionDuration, - children, -}: SpoilerProps) => { - const { t } = useTranslation(); +export const Spoiler = ({ maxHeight, defaultOpened, children, ...props }: SpoilerProps) => { + const ref = useRef(null); + const isOverflow = useIsOverflow(ref); + const [isExpanded, setIsExpanded] = useState(!!defaultOpened); + + const spoilerClassNames = clsx(styles.spoiler, { + [styles.canExpand]: isOverflow, + [styles.isExpanded]: isExpanded, + }); + + const handleToggleExpand = () => { + setIsExpanded((val) => !val); + }; return ( - {children} - + ); }; diff --git a/src/renderer/components/spoiler/spoiler.module.scss b/src/renderer/components/spoiler/spoiler.module.scss index a7b51068..36bd1796 100644 --- a/src/renderer/components/spoiler/spoiler.module.scss +++ b/src/renderer/components/spoiler/spoiler.module.scss @@ -1,9 +1,31 @@ -.control { - color: var(--btn-subtle-fg); - font-weight: 600; -} - .control:hover { color: var(--btn-subtle-fg-hover); text-decoration: none; } + +.spoiler { + position: relative; + text-align: justify; + width: 100%; + height: 100%; + overflow: hidden; +} + +.spoiler:not(.is-expanded).can-expand:after { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 100%; + content: ''; + background: linear-gradient(to top, var(--main-bg) 10%, transparent 60%); + pointer-events: none; +} + +.spoiler.can-expand { + cursor: pointer; +} + +.spoiler.is-expanded { + max-height: 2500px !important; +} diff --git a/src/renderer/hooks/index.ts b/src/renderer/hooks/index.ts index 82dd033a..0bc18aeb 100644 --- a/src/renderer/hooks/index.ts +++ b/src/renderer/hooks/index.ts @@ -5,3 +5,4 @@ export * from './use-container-query'; export * from './use-fast-average-color'; export * from './use-hide-scrollbar'; export * from './use-app-focus'; +export * from './use-is-overflow'; diff --git a/src/renderer/hooks/use-is-overflow.ts b/src/renderer/hooks/use-is-overflow.ts new file mode 100644 index 00000000..a3c0b7d0 --- /dev/null +++ b/src/renderer/hooks/use-is-overflow.ts @@ -0,0 +1,20 @@ +import { MutableRefObject, useState, useLayoutEffect } from 'react'; + +export const useIsOverflow = (ref: MutableRefObject) => { + const [isOverflow, setIsOverflow] = useState(undefined); + + useLayoutEffect(() => { + const { current } = ref; + + const trigger = () => { + const hasOverflow = (current?.scrollHeight || 0) > (current?.clientHeight || 0); + setIsOverflow(hasOverflow); + }; + + if (current) { + trigger(); + } + }, [ref]); + + return isOverflow; +};