forked from Archives/Athou_commafeed
update to mantine 7
This commit is contained in:
@@ -67,7 +67,7 @@ export function AboutPage() {
|
||||
|
||||
return (
|
||||
<Container size="xl">
|
||||
<SimpleGrid cols={2} breakpoints={[{ maxWidth: Constants.layout.mobileBreakpoint, cols: 1 }]}>
|
||||
<SimpleGrid cols={{ base: 1, [Constants.layout.mobileBreakpointName]: 2 }}>
|
||||
<Section title={<Trans>About</Trans>} icon={<TbHelp size={24} />}>
|
||||
<Box>
|
||||
<Trans>
|
||||
|
||||
@@ -10,13 +10,13 @@ export function AddPage() {
|
||||
<Container size="sm" px={0}>
|
||||
<Tabs defaultValue="subscribe">
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="subscribe" icon={<TbRss size={16} />}>
|
||||
<Tabs.Tab value="subscribe" leftSection={<TbRss size={16} />}>
|
||||
<Trans>Subscribe</Trans>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="category" icon={<TbFolderPlus size={16} />}>
|
||||
<Tabs.Tab value="category" leftSection={<TbFolderPlus size={16} />}>
|
||||
<Trans>Add category</Trans>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="opml" icon={<TbFileImport size={16} />}>
|
||||
<Tabs.Tab value="opml" leftSection={<TbFileImport size={16} />}>
|
||||
<Trans>OPML</Trans>
|
||||
</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
|
||||
@@ -127,13 +127,13 @@ export function CategoryDetailsPage() {
|
||||
</Button>
|
||||
{editable && (
|
||||
<>
|
||||
<Button type="submit" leftIcon={<TbDeviceFloppy size={16} />} loading={modifyCategory.loading}>
|
||||
<Button type="submit" leftSection={<TbDeviceFloppy size={16} />} loading={modifyCategory.loading}>
|
||||
<Trans>Save</Trans>
|
||||
</Button>
|
||||
<Divider orientation="vertical" />
|
||||
<Button
|
||||
color="red"
|
||||
leftIcon={<TbTrash size={16} />}
|
||||
leftSection={<TbTrash size={16} />}
|
||||
onClick={() => openDeleteCategoryModal()}
|
||||
loading={deleteCategory.loading}
|
||||
>
|
||||
|
||||
@@ -166,13 +166,13 @@ export function FeedDetailsPage() {
|
||||
<Button variant="default" onClick={async () => await dispatch(redirectToSelectedSource())}>
|
||||
<Trans>Cancel</Trans>
|
||||
</Button>
|
||||
<Button type="submit" leftIcon={<TbDeviceFloppy size={16} />} loading={modifyFeed.loading}>
|
||||
<Button type="submit" leftSection={<TbDeviceFloppy size={16} />} loading={modifyFeed.loading}>
|
||||
<Trans>Save</Trans>
|
||||
</Button>
|
||||
<Divider orientation="vertical" />
|
||||
<Button
|
||||
color="red"
|
||||
leftIcon={<TbTrash size={16} />}
|
||||
leftSection={<TbTrash size={16} />}
|
||||
onClick={() => openUnsubscribeModal()}
|
||||
loading={unsubscribe.loading}
|
||||
>
|
||||
|
||||
@@ -73,7 +73,7 @@ export function FeedEntriesPage(props: FeedEntriesPageProps) {
|
||||
return (
|
||||
// add some room at the bottom of the page in order to be able to scroll the current entry at the top of the page when expanding
|
||||
<Box mb={viewport.height - Constants.layout.headerHeight - 210}>
|
||||
<Group spacing="xl">
|
||||
<Group gap="xl">
|
||||
{sourceWebsiteUrl && (
|
||||
<a href={sourceWebsiteUrl} target="_blank" rel="noreferrer" className={classes.sourceWebsiteLink}>
|
||||
<Title order={3}>{sourceLabel}</Title>
|
||||
|
||||
@@ -1,88 +1,32 @@
|
||||
import {
|
||||
ActionIcon,
|
||||
AppShell,
|
||||
Box,
|
||||
Burger,
|
||||
Center,
|
||||
DEFAULT_THEME,
|
||||
Group,
|
||||
Header,
|
||||
type MantineTheme,
|
||||
Navbar,
|
||||
ScrollArea,
|
||||
Title,
|
||||
useMantineTheme,
|
||||
} from "@mantine/core"
|
||||
import { Trans } from "@lingui/macro"
|
||||
import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core"
|
||||
import { Constants } from "app/constants"
|
||||
import { redirectToAdd, redirectToRootCategory } from "app/redirect/thunks"
|
||||
import { useAppDispatch, useAppSelector } from "app/store"
|
||||
import { setMobileMenuOpen, setSidebarWidth } from "app/tree/slice"
|
||||
import { reloadTree } from "app/tree/thunks"
|
||||
import { reloadProfile, reloadSettings, reloadTags } from "app/user/thunks"
|
||||
import { ActionButton } from "components/ActionButton"
|
||||
import { AnnouncementDialog } from "components/AnnouncementDialog"
|
||||
import { Loader } from "components/Loader"
|
||||
import { Logo } from "components/Logo"
|
||||
import { OnDesktop } from "components/responsive/OnDesktop"
|
||||
import { OnMobile } from "components/responsive/OnMobile"
|
||||
import { useAppLoading } from "hooks/useAppLoading"
|
||||
import { useMobile } from "hooks/useMobile"
|
||||
import { useWebSocket } from "hooks/useWebSocket"
|
||||
import { LoadingPage } from "pages/LoadingPage"
|
||||
import { Resizable } from "re-resizable"
|
||||
import { type ReactNode, Suspense, useEffect } from "react"
|
||||
import { TbPlus } from "react-icons/tb"
|
||||
import Draggable from "react-draggable"
|
||||
import { TbMenu2, TbPlus, TbX } from "react-icons/tb"
|
||||
import { Outlet } from "react-router-dom"
|
||||
import { tss } from "tss"
|
||||
|
||||
interface LayoutProps {
|
||||
sidebar: ReactNode
|
||||
sidebarWidth: number
|
||||
sidebarVisible: boolean
|
||||
header: ReactNode
|
||||
}
|
||||
|
||||
const sidebarPadding = DEFAULT_THEME.spacing.xs
|
||||
const sidebarRightBorderWidth = "1px"
|
||||
|
||||
const useStyles = tss
|
||||
.withParams<{
|
||||
theme: MantineTheme
|
||||
sidebarWidth: number
|
||||
}>()
|
||||
.create(({ theme, sidebarWidth }) => ({
|
||||
sidebar: {
|
||||
"& .mantine-ScrollArea-scrollbar[data-orientation='horizontal']": {
|
||||
display: "none",
|
||||
},
|
||||
},
|
||||
sidebarContentResizeWrapper: {
|
||||
padding: sidebarPadding,
|
||||
minHeight: `calc(100vh - ${Constants.layout.headerHeight}px)`,
|
||||
},
|
||||
sidebarContent: {
|
||||
maxWidth: `calc(${sidebarWidth}px - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||
maxWidth: `calc(100vw - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`,
|
||||
},
|
||||
},
|
||||
mainContentWrapper: {
|
||||
paddingTop: Constants.layout.headerHeight,
|
||||
paddingLeft: sidebarWidth,
|
||||
paddingRight: 0,
|
||||
paddingBottom: 0,
|
||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||
paddingLeft: 0,
|
||||
},
|
||||
},
|
||||
mainContent: {
|
||||
maxWidth: `calc(100vw - ${sidebarWidth}px)`,
|
||||
padding: theme.spacing.md,
|
||||
[theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: {
|
||||
maxWidth: "100vw",
|
||||
padding: "6px",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
function LogoAndTitle() {
|
||||
const dispatch = useAppDispatch()
|
||||
return (
|
||||
@@ -97,21 +41,13 @@ function LogoAndTitle() {
|
||||
|
||||
export default function Layout(props: LayoutProps) {
|
||||
const theme = useMantineTheme()
|
||||
const { classes } = useStyles({
|
||||
theme,
|
||||
sidebarWidth: props.sidebarWidth,
|
||||
})
|
||||
const { loading } = useAppLoading()
|
||||
const mobile = useMobile()
|
||||
const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen)
|
||||
const webSocketConnected = useAppSelector(state => state.server.webSocketConnected)
|
||||
const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval)
|
||||
const sidebarHidden = props.sidebarWidth === 0
|
||||
const dispatch = useAppDispatch()
|
||||
useWebSocket()
|
||||
|
||||
const handleResize = (element: HTMLElement) => dispatch(setSidebarWidth(element.offsetWidth))
|
||||
|
||||
useEffect(() => {
|
||||
// load initial data
|
||||
dispatch(reloadSettings())
|
||||
@@ -132,18 +68,20 @@ export default function Layout(props: LayoutProps) {
|
||||
}, [dispatch, webSocketConnected, treeReloadInterval])
|
||||
|
||||
const burger = (
|
||||
<Center>
|
||||
<Burger
|
||||
color={theme.fn.variant({ color: theme.primaryColor, variant: "subtle" }).color}
|
||||
opened={mobileMenuOpen}
|
||||
onClick={() => dispatch(setMobileMenuOpen(!mobileMenuOpen))}
|
||||
size="sm"
|
||||
/>
|
||||
</Center>
|
||||
<ActionButton
|
||||
label={mobileMenuOpen ? <Trans>Open menu</Trans> : <Trans>Close menu</Trans>}
|
||||
icon={mobileMenuOpen ? <TbX size={18} /> : <TbMenu2 size={18} />}
|
||||
onClick={() => dispatch(setMobileMenuOpen(!mobileMenuOpen))}
|
||||
></ActionButton>
|
||||
)
|
||||
|
||||
const addButton = (
|
||||
<ActionIcon color={theme.primaryColor} onClick={async () => await dispatch(redirectToAdd())} aria-label="Subscribe">
|
||||
<ActionIcon
|
||||
color={theme.primaryColor}
|
||||
variant="subtle"
|
||||
onClick={async () => await dispatch(redirectToAdd())}
|
||||
aria-label="Subscribe"
|
||||
>
|
||||
<TbPlus size={18} />
|
||||
</ActionIcon>
|
||||
)
|
||||
@@ -151,77 +89,80 @@ export default function Layout(props: LayoutProps) {
|
||||
if (loading) return <LoadingPage />
|
||||
return (
|
||||
<AppShell
|
||||
fixed
|
||||
navbarOffsetBreakpoint={Constants.layout.mobileBreakpoint}
|
||||
classNames={{ main: classes.mainContentWrapper }}
|
||||
navbar={
|
||||
<Navbar
|
||||
id="sidebar"
|
||||
hiddenBreakpoint={sidebarHidden ? 99999999 : Constants.layout.mobileBreakpoint}
|
||||
hidden={sidebarHidden || !mobileMenuOpen}
|
||||
width={{ md: props.sidebarWidth }}
|
||||
className={classes.sidebar}
|
||||
>
|
||||
<Navbar.Section grow component={ScrollArea} mx={mobile ? 0 : "-sm"} px={mobile ? 0 : "sm"}>
|
||||
<Resizable
|
||||
enable={{
|
||||
top: false,
|
||||
right: !mobile,
|
||||
bottom: false,
|
||||
left: false,
|
||||
topRight: false,
|
||||
bottomRight: false,
|
||||
bottomLeft: false,
|
||||
topLeft: false,
|
||||
}}
|
||||
onResize={(e, dir, el) => handleResize(el)}
|
||||
minWidth={120}
|
||||
className={classes.sidebarContentResizeWrapper}
|
||||
>
|
||||
<Box className={classes.sidebarContent}>{props.sidebar}</Box>
|
||||
</Resizable>
|
||||
</Navbar.Section>
|
||||
</Navbar>
|
||||
}
|
||||
header={
|
||||
<Header id="header" height={Constants.layout.headerHeight} p="md">
|
||||
<OnMobile>
|
||||
{mobileMenuOpen && (
|
||||
<Group position="apart">
|
||||
<Box>{burger}</Box>
|
||||
<Box>
|
||||
<LogoAndTitle />
|
||||
</Box>
|
||||
<Box>{addButton}</Box>
|
||||
</Group>
|
||||
)}
|
||||
{!mobileMenuOpen && (
|
||||
<Group>
|
||||
<Box>{burger}</Box>
|
||||
<Box sx={{ flexGrow: 1 }}>{props.header}</Box>
|
||||
</Group>
|
||||
)}
|
||||
</OnMobile>
|
||||
<OnDesktop>
|
||||
<Group>
|
||||
<Group position="apart" sx={{ width: props.sidebarWidth - 16 }}>
|
||||
<Box>
|
||||
<LogoAndTitle />
|
||||
</Box>
|
||||
<Box>{addButton}</Box>
|
||||
</Group>
|
||||
<Box sx={{ flexGrow: 1 }}>{props.header}</Box>
|
||||
</Group>
|
||||
</OnDesktop>
|
||||
</Header>
|
||||
}
|
||||
header={{ height: Constants.layout.headerHeight }}
|
||||
navbar={{
|
||||
width: props.sidebarWidth,
|
||||
breakpoint: Constants.layout.mobileBreakpoint,
|
||||
collapsed: { mobile: !mobileMenuOpen, desktop: !props.sidebarVisible },
|
||||
}}
|
||||
padding={{ base: 6, [Constants.layout.mobileBreakpointName]: "md" }}
|
||||
>
|
||||
<Box id="content" className={classes.mainContent}>
|
||||
<AppShell.Header id="header">
|
||||
<OnMobile>
|
||||
{mobileMenuOpen && (
|
||||
<Group justify="space-between" p="md">
|
||||
<Box>{burger}</Box>
|
||||
<Box>
|
||||
<LogoAndTitle />
|
||||
</Box>
|
||||
<Box>{addButton}</Box>
|
||||
</Group>
|
||||
)}
|
||||
{!mobileMenuOpen && (
|
||||
<Group p="md">
|
||||
<Box>{burger}</Box>
|
||||
<Box style={{ flexGrow: 1 }}>{props.header}</Box>
|
||||
</Group>
|
||||
)}
|
||||
</OnMobile>
|
||||
<OnDesktop>
|
||||
<Group p="md">
|
||||
<Group justify="space-between" style={{ width: props.sidebarWidth - 16 }}>
|
||||
<Box>
|
||||
<LogoAndTitle />
|
||||
</Box>
|
||||
<Box>{addButton}</Box>
|
||||
</Group>
|
||||
<Box style={{ flexGrow: 1 }}>{props.header}</Box>
|
||||
</Group>
|
||||
</OnDesktop>
|
||||
</AppShell.Header>
|
||||
<AppShell.Navbar id="sidebar" p="xs">
|
||||
<AppShell.Section grow component={ScrollArea} mx="-sm" px="sm">
|
||||
<Box>{props.sidebar}</Box>
|
||||
</AppShell.Section>
|
||||
</AppShell.Navbar>
|
||||
<Draggable
|
||||
axis="x"
|
||||
defaultPosition={{
|
||||
x: props.sidebarWidth,
|
||||
y: Constants.layout.headerHeight,
|
||||
}}
|
||||
bounds={{
|
||||
left: 120,
|
||||
right: 1000,
|
||||
}}
|
||||
grid={[30, 30]}
|
||||
onDrag={(_e, data) => {
|
||||
dispatch(setSidebarWidth(data.x))
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
style={{
|
||||
position: "fixed",
|
||||
height: "100%",
|
||||
width: "10px",
|
||||
cursor: "ew-resize",
|
||||
}}
|
||||
></Box>
|
||||
</Draggable>
|
||||
|
||||
<AppShell.Main id="content">
|
||||
<Suspense fallback={<Loader />}>
|
||||
<AnnouncementDialog />
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
</Box>
|
||||
</AppShell.Main>
|
||||
</AppShell>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,13 @@ export function SettingsPage() {
|
||||
<Container size="sm" px={0}>
|
||||
<Tabs defaultValue="display" keepMounted={false}>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="display" icon={<TbPhoto size={16} />}>
|
||||
<Tabs.Tab value="display" leftSection={<TbPhoto size={16} />}>
|
||||
<Trans>Display</Trans>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="customCode" icon={<TbCode size={16} />}>
|
||||
<Tabs.Tab value="customCode" leftSection={<TbCode size={16} />}>
|
||||
<Trans>Custom code</Trans>
|
||||
</Tabs.Tab>
|
||||
<Tabs.Tab value="profile" icon={<TbUser size={16} />}>
|
||||
<Tabs.Tab value="profile" leftSection={<TbUser size={16} />}>
|
||||
<Trans>Profile</Trans>
|
||||
</Tabs.Tab>
|
||||
</Tabs.List>
|
||||
|
||||
Reference in New Issue
Block a user