parent
7b349895b1
commit
7928e0faf3
|
|
@ -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="M4 20 20 4"/></svg>
|
||||
|
After Width: | Height: | Size: 216 B |
|
|
@ -10,8 +10,8 @@ describe("test route builder", () => {
|
|||
"./pages/(external)/layout.tsx": fakePromise,
|
||||
"./pages/(external)/(with-layout)/index.tsx": fakePromise,
|
||||
"./pages/(external)/(with-layout)/layout.tsx": fakePromise,
|
||||
"./pages/(external)/(with-layout)/feed/[:id]/index.tsx": fakePromise,
|
||||
"./pages/(external)/(with-layout)/feed/[:id]/layout.tsx": fakePromise,
|
||||
"./pages/(external)/(with-layout)/feed/[id]/index.tsx": fakePromise,
|
||||
"./pages/(external)/(with-layout)/feed/[id]/layout.tsx": fakePromise,
|
||||
|
||||
"./pages/(main)/layout.tsx": fakePromise,
|
||||
"./pages/(main)/(context)/layout.tsx": fakePromise,
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ const normalizePathKey = (key: string) => {
|
|||
return ""
|
||||
}
|
||||
|
||||
if (key.startsWith("[:") && key.endsWith("]")) {
|
||||
if (key.startsWith("[") && key.endsWith("]")) {
|
||||
return `:${key.slice(2, -1)}`
|
||||
}
|
||||
return key
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
useUnreadStore,
|
||||
} from "@renderer/store"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { FeedForm } from "../discover/feed-form"
|
||||
|
|
@ -97,6 +98,7 @@ export function FeedItem({
|
|||
|
||||
const feedUnread = useUnreadStore((state) => state.data[feed.feedId] || 0)
|
||||
const { present } = useModalStack()
|
||||
const navigate = useNavigate()
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
|
|
@ -109,6 +111,7 @@ export function FeedItem({
|
|||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setFeedActive(feed)
|
||||
navigate(`/feeds/${feed.feedId}`)
|
||||
}}
|
||||
onDoubleClick={() => {
|
||||
window.open(
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
import { setMainContainerElement } from "@renderer/atoms"
|
||||
import { FeedColumn } from "@renderer/modules/feed-column"
|
||||
import { Outlet } from "react-router-dom"
|
||||
|
||||
export function Component() {
|
||||
return (
|
||||
<div className="flex h-full">
|
||||
<div className="w-64 shrink-0 border-r">
|
||||
<FeedColumn />
|
||||
</div>
|
||||
{/* NOTE: tabIndex for main element can get by `document.activeElement` */}
|
||||
<main ref={setMainContainerElement} className="flex min-w-0 flex-1 bg-theme-background !outline-none" tabIndex={-1}>
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -3,13 +3,12 @@ import { cn } from "@renderer/lib/utils"
|
|||
import { EntryColumn } from "@renderer/modules/entry-column"
|
||||
import { EntryContent } from "@renderer/modules/entry-content"
|
||||
import {
|
||||
feedActions,
|
||||
uiActions,
|
||||
useFeedStore,
|
||||
useUIStore,
|
||||
} from "@renderer/store"
|
||||
import { AnimatePresence } from "framer-motion"
|
||||
import { useEffect, useMemo, useRef } from "react"
|
||||
import { useMemo, useRef } from "react"
|
||||
import { useResizable } from "react-resizable-layout"
|
||||
import { useShallow } from "zustand/react/shallow"
|
||||
|
||||
|
|
@ -20,10 +19,7 @@ export function Component() {
|
|||
activeEntry: state.activeEntryId,
|
||||
})),
|
||||
)
|
||||
const { setActiveEntry } = feedActions
|
||||
useEffect(() => {
|
||||
setActiveEntry(null)
|
||||
}, [activeList?.id])
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Memo this initial value to avoid re-render
|
||||
|
|
@ -0,0 +1 @@
|
|||
export { Outlet as Component } from "react-router-dom"
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import { views } from "@renderer/lib/constants"
|
||||
import { cn } from "@renderer/lib/utils"
|
||||
import { EntryColumn } from "@renderer/modules/entry-column"
|
||||
import { EntryContent } from "@renderer/modules/entry-content"
|
||||
import {
|
||||
uiActions,
|
||||
useFeedStore,
|
||||
useUIStore,
|
||||
} from "@renderer/store"
|
||||
import { AnimatePresence } from "framer-motion"
|
||||
import { useMemo, useRef } from "react"
|
||||
import { useResizable } from "react-resizable-layout"
|
||||
import { useShallow } from "zustand/react/shallow"
|
||||
|
||||
export function Component() {
|
||||
const { activeEntry, activeList } = useFeedStore(
|
||||
useShallow((state) => ({
|
||||
activeList: state.activeList,
|
||||
activeEntry: state.activeEntryId,
|
||||
})),
|
||||
)
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
// Memo this initial value to avoid re-render
|
||||
// eslint-disable-next-line react-compiler/react-compiler
|
||||
const entryColWidth = useMemo(() => useUIStore.getState().entryColWidth, [])
|
||||
|
||||
const { position, separatorProps } = useResizable({
|
||||
axis: "x",
|
||||
min: 300,
|
||||
max: 450,
|
||||
initial: entryColWidth,
|
||||
containerRef,
|
||||
onResizeEnd({ position }) {
|
||||
uiActions.setEntryColWidth(position)
|
||||
},
|
||||
})
|
||||
|
||||
const inWideMode = activeList && views[activeList.view].wideMode
|
||||
return (
|
||||
<div ref={containerRef} className="flex min-w-0 grow">
|
||||
<div
|
||||
className={cn(
|
||||
"h-full shrink-0 overflow-y-auto",
|
||||
inWideMode ? "flex-1" : "border-r",
|
||||
"will-change-[width]",
|
||||
)}
|
||||
style={{
|
||||
width: position,
|
||||
}}
|
||||
>
|
||||
<EntryColumn />
|
||||
</div>
|
||||
{!inWideMode && (
|
||||
<div
|
||||
{...separatorProps}
|
||||
className="h-full w-px shrink-0 cursor-ew-resize hover:bg-border"
|
||||
/>
|
||||
)}
|
||||
<AnimatePresence>
|
||||
{!inWideMode && (
|
||||
<div className="min-w-0 flex-1">
|
||||
<EntryContent entry={activeEntry} />
|
||||
</div>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,22 +1,17 @@
|
|||
import { feedActions, useFeedStore } from "@renderer/store"
|
||||
import { useEffect } from "react"
|
||||
import { Outlet, useNavigate } from "react-router-dom"
|
||||
import { setMainContainerElement } from "@renderer/atoms"
|
||||
import { FeedColumn } from "@renderer/modules/feed-column"
|
||||
import { Outlet } from "react-router-dom"
|
||||
|
||||
function MainLayout() {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const changed = useFeedStore(
|
||||
(state) => `${state.activeList?.view}-${state.activeList?.id}`,
|
||||
export function Component() {
|
||||
return (
|
||||
<div className="flex h-full">
|
||||
<div className="w-64 shrink-0 border-r">
|
||||
<FeedColumn />
|
||||
</div>
|
||||
{/* NOTE: tabIndex for main element can get by `document.activeElement` */}
|
||||
<main ref={setMainContainerElement} className="flex min-w-0 flex-1 bg-theme-background !outline-none" tabIndex={-1}>
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
feedActions.setActiveEntry(null)
|
||||
if (changed) {
|
||||
navigate("/")
|
||||
}
|
||||
}, [changed])
|
||||
|
||||
return <Outlet />
|
||||
}
|
||||
|
||||
export { MainLayout as Component }
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { buildGlobRoutes } from "./lib/route-builder"
|
|||
|
||||
const globTree = import.meta.glob("./pages/**/*.tsx")
|
||||
const tree = buildGlobRoutes(globTree)
|
||||
// console.log(tree)
|
||||
|
||||
export const router = createBrowserRouter([
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue