refactor: entry content gird container
Signed-off-by: Innei <i@innei.in>
This commit is contained in:
parent
0c582f24e7
commit
097e6dd4a5
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -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": "提供三种认证方式,选择其中一种继续:",
|
||||
|
|
|
|||
Loading…
Reference in New Issue