refactor: entry content gird container

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-10-06 18:15:28 +08:00
parent 0c582f24e7
commit 097e6dd4a5
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
9 changed files with 103 additions and 62 deletions

View File

@ -26,6 +26,7 @@ interface ActionButtonProps {
active?: boolean
disabled?: boolean
shortcut?: string
disableTriggerShortcut?: boolean
}
export const ActionButton = React.forwardRef<
@ -43,6 +44,7 @@ export const ActionButton = React.forwardRef<
active,
shortcut,
disabled,
disableTriggerShortcut,
...rest
},
ref,
@ -78,7 +80,9 @@ export const ActionButton = React.forwardRef<
)
return (
<>
{shortcut && <HotKeyTrigger shortcut={shortcut} fn={() => buttonRef.current?.click()} />}
{shortcut && !disableTriggerShortcut && (
<HotKeyTrigger shortcut={shortcut} fn={() => buttonRef.current?.click()} />
)}
{tooltip ? (
<Tooltip disableHoverableContent>
<TooltipTrigger asChild>{Trigger}</TooltipTrigger>

View File

@ -18,18 +18,21 @@ const SpecialKeys = {
ctrl: "Ctrl",
alt: "Alt",
shift: "Shift",
escape: "Esc",
},
macOS: {
meta: "⌘",
ctrl: "⌃",
alt: "⌥",
shift: "⇧",
escape: "⎋",
},
Linux: {
meta: "Super",
ctrl: "Ctrl",
alt: "Alt",
shift: "Shift",
escape: "Escape",
},
}
// @ts-ignore

View File

@ -257,9 +257,7 @@ const WideModeButton = () => {
: t("entry_list_header.switch_to_normalmode")
}
>
<i
className={cn(isWideMode ? "i-mgc-align-justify-cute-re" : "i-mgc-align-left-cute-re")}
/>
<i className={cn(isWideMode ? "i-mgc-align-justify-cute-re" : "i-mgc-layout-4-cute-re")} />
</ActionButton>
</ImpressionView>
)

View File

@ -22,6 +22,11 @@ import { useUserById } from "~/store/user"
import { usePresentUserProfileModal } from "../../profile/hooks"
const getLimit = (width: number): number => {
if (width > 900) return 15
if (width > 600) return 10
return 5
}
export const EntryReadHistory: Component<{ entryId: string }> = ({ entryId }) => {
const me = useWhoami()
const entryHistory = useEntryReadHistory(entryId)
@ -33,7 +38,7 @@ export const EntryReadHistory: Component<{ entryId: string }> = ({ entryId }) =>
const appGirdContainerWidth = useAppLayoutGridContainerWidth()
const LIMIT = appGirdContainerWidth > 600 ? 10 : 5
const LIMIT = getLimit(appGirdContainerWidth)
if (!entryHistory) return null
if (!me) return null
@ -56,7 +61,7 @@ export const EntryReadHistory: Component<{ entryId: string }> = ({ entryId }) =>
type="button"
style={{
right: `${LIMIT * 8}px`,
zIndex: 11,
zIndex: LIMIT + 1,
}}
className="no-drag-region relative flex size-7 items-center justify-center rounded-full border border-border bg-muted ring-2 ring-background"
>

View File

@ -67,9 +67,12 @@ export const EntryContent = ({
}) => {
const title = useFeedHeaderTitle()
const { feedId, view } = useRouteParams()
const enableEntryWideMode = useUISettingKey("wideMode")
useTitle(title)
if (!entryId) {
if (enableEntryWideMode) {
return null
}
return (
<m.div
className="center size-full flex-col"

View File

@ -1,6 +1,7 @@
import { useWheel } from "@use-gesture/react"
import { AnimatePresence, easeOut } from "framer-motion"
import { useRef } from "react"
import type { FC, PropsWithChildren } from "react"
import { useState } from "react"
import { useHotkeys } from "react-hotkeys-hook"
import { useParams } from "react-router-dom"
@ -22,8 +23,8 @@ export const Component = () => {
const settingWideMode = useUISettingKey("wideMode")
const realEntryId = entryId === ROUTE_ENTRY_PENDING ? "" : entryId
const inEntryContentWideMode = !(views[view].wideMode || (settingWideMode && !realEntryId))
const wideMode = settingWideMode && realEntryId
const showEntryContent = !(views[view].wideMode || (settingWideMode && !realEntryId))
const wideMode = !!(settingWideMode && realEntryId)
const feedColumnTempShow = useFeedColumnTempShow()
const feedColumnShow = useFeedColumnShow()
const shouldHeaderPaddingLeft = feedColumnTempShow && !feedColumnShow && settingWideMode
@ -31,18 +32,68 @@ export const Component = () => {
useHotkeys(
"Escape",
() => {
if (inEntryContentWideMode) {
if (settingWideMode) {
navigate({ entryId: null })
}
},
{
enabled: inEntryContentWideMode,
enabled: showEntryContent,
scopes: HotKeyScopeMap.Home,
preventDefault: true,
},
)
const carouselRef = useRef<HTMLDivElement>(null)
if (!showEntryContent) {
return null
}
return (
<AnimatePresence mode="popLayout">
<AppLayoutGridContainerProvider>
<EntryGridContainer showEntryContent={showEntryContent} wideMode={wideMode}>
{wideMode && (
// Close button
<ActionButton
className={cn(
"absolute left-3 top-3 z-10 duration-200",
shouldHeaderPaddingLeft
? "left-[calc(theme(width.3)+theme(width.feed-col))]"
: "left-3",
)}
tooltip="Close"
shortcut="Escape"
disableTriggerShortcut
onClick={() => navigate({ entryId: null })}
>
<i className="i-mgc-close-cute-re size-5" />
</ActionButton>
)}
<EntryContent
entryId={realEntryId}
classNames={{
header: shouldHeaderPaddingLeft
? "ml-[calc(theme(width.feed-col)+theme(width.8))]"
: wideMode
? "ml-8"
: "",
}}
/>
</EntryGridContainer>
</AppLayoutGridContainerProvider>
</AnimatePresence>
)
}
const EntryGridContainer: FC<
PropsWithChildren<{
showEntryContent: boolean
wideMode: boolean
}>
> = ({ children, showEntryContent, wideMode }) => {
const [containerRef, setContainerRef] = useState<HTMLDivElement | null>()
const navigate = useNavigateEntry()
useWheel(
({ delta: [dex] }) => {
if (dex < -50) {
@ -50,56 +101,32 @@ export const Component = () => {
}
},
{
enabled: inEntryContentWideMode,
target: carouselRef,
enabled: showEntryContent && wideMode,
target: containerRef!,
eventOptions: { capture: true },
axis: "x",
},
)
return (
<AnimatePresence>
<AppLayoutGridContainerProvider>
<AnimatePresence>
{inEntryContentWideMode && (
<m.div
ref={carouselRef}
// slide up
initial={{ opacity: 0, y: 100 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 100, transition: { duration: 0.2, ease: easeOut } }}
transition={{ duration: 0.2, type: "spring" }}
className={cn(
"flex min-w-0 flex-1 flex-col",
wideMode && "absolute inset-0 z-10 bg-theme-background",
)}
>
{wideMode && (
<ActionButton
className={cn(
"absolute left-3 top-3 z-10 duration-200",
shouldHeaderPaddingLeft
? "left-[calc(theme(width.3)+theme(width.feed-col))]"
: "left-3",
)}
onClick={() => navigate({ entryId: null })}
>
<i className="i-mgc-close-cute-re size-5" />
</ActionButton>
)}
<EntryContent
entryId={realEntryId}
classNames={{
header: shouldHeaderPaddingLeft
? "ml-[calc(theme(width.feed-col)+theme(width.8))]"
: "ml-8",
}}
/>
</m.div>
)}
</AnimatePresence>
</AppLayoutGridContainerProvider>
</AnimatePresence>
)
if (wideMode) {
return (
<m.div
ref={setContainerRef}
// slide up
initial={{ opacity: 0, y: 100 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 100, transition: { duration: 0.2, ease: easeOut } }}
transition={{ duration: 0.2, type: "spring" }}
className={cn("flex min-w-0 flex-1 flex-col", "absolute inset-0 z-10 bg-theme-background")}
>
{children}
</m.div>
)
} else {
return (
<div ref={setContainerRef} className="flex min-w-0 flex-1 flex-col">
{children}
</div>
)
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none"><path fill="#fff" fill-opacity=".01" d="M24 0v24H0V0z"/><path stroke="#10161F" stroke-linecap="round" stroke-width="2" d="M9 3.5a87.692 87.692 0 0 0 0 17M13 8h3m-3 4h3m-3 4h3m4.5-4.5v1c0 3.771 0 5.657-1.172 6.828C18.157 20.5 16.271 20.5 12.5 20.5h-1c-3.771 0-5.657 0-6.828-1.172C3.5 18.157 3.5 16.271 3.5 12.5v-1c0-3.771 0-5.657 1.172-6.828C5.843 3.5 7.729 3.5 11.5 3.5h1c3.771 0 5.657 0 6.828 1.172C20.5 5.843 20.5 7.729 20.5 11.5Z"/></svg>

After

Width:  |  Height:  |  Size: 516 B

View File

@ -99,7 +99,7 @@
"entry_list_header.show_unread_only": "Show unread Only",
"entry_list_header.switch_to_grid": "Switch to Grid",
"entry_list_header.switch_to_masonry": "Switch to Masonry",
"entry_list_header.switch_to_normalmode": "Switch to Normal Mode",
"entry_list_header.switch_to_normalmode": "Switch to Double Column Mode",
"entry_list_header.switch_to_widemode": "Switch to Wide Mode",
"entry_list_header.unread": "unread",
"feed_claim_modal.choose_verification_method": "There are three ways to choose from, you can choose one of them to verify.",

View File

@ -99,7 +99,7 @@
"entry_list_header.show_unread_only": "仅显示未读",
"entry_list_header.switch_to_grid": "切换到网格",
"entry_list_header.switch_to_masonry": "切换到瀑布流",
"entry_list_header.switch_to_normalmode": "切换到正常模式",
"entry_list_header.switch_to_normalmode": "切换到双列模式",
"entry_list_header.switch_to_widemode": "切换到宽屏模式",
"entry_list_header.unread": "未读",
"feed_claim_modal.choose_verification_method": "提供三种认证方式,选择其中一种继续:",