diff --git a/commafeed-client/package-lock.json b/commafeed-client/package-lock.json index a4d24875..b4a702e4 100644 --- a/commafeed-client/package-lock.json +++ b/commafeed-client/package-lock.json @@ -42,6 +42,7 @@ "redoc": "^2.1.3", "throttle-debounce": "^5.0.0", "tinycon": "^0.6.8", + "tss-react": "^4.9.3", "use-local-storage": "^3.0.0", "websocket-heartbeat-js": "^1.1.3" }, @@ -8034,6 +8035,30 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/tss-react": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/tss-react/-/tss-react-4.9.3.tgz", + "integrity": "sha512-TqI0kBFmgW0f5YIOD2PMdHu6FnqSxVDUf5uJ7+gVkhemtMfwdlFpvXpddgSesktizr9PU9hY2nZ+kNnf0KQb9A==", + "dependencies": { + "@emotion/cache": "*", + "@emotion/serialize": "*", + "@emotion/utils": "*" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/server": "^11.4.0", + "@mui/material": "^5.0.0", + "react": "^16.8.0 || ^17.0.2 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/server": { + "optional": true + }, + "@mui/material": { + "optional": true + } + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/commafeed-client/package.json b/commafeed-client/package.json index 1ea61603..f3512afe 100644 --- a/commafeed-client/package.json +++ b/commafeed-client/package.json @@ -48,6 +48,7 @@ "redoc": "^2.1.3", "throttle-debounce": "^5.0.0", "tinycon": "^0.6.8", + "tss-react": "^4.9.3", "use-local-storage": "^3.0.0", "websocket-heartbeat-js": "^1.1.3" }, diff --git a/commafeed-client/src/components/ImageWithPlaceholderWhileLoading.tsx b/commafeed-client/src/components/ImageWithPlaceholderWhileLoading.tsx index 9a50e64f..67a7b426 100644 --- a/commafeed-client/src/components/ImageWithPlaceholderWhileLoading.tsx +++ b/commafeed-client/src/components/ImageWithPlaceholderWhileLoading.tsx @@ -1,6 +1,7 @@ -import { Box, Center, createStyles } from "@mantine/core" +import { Box, Center, type MantineTheme, useMantineTheme } from "@mantine/core" import { useState } from "react" import { TbPhoto } from "react-icons/tb" +import { tss } from "tss" interface ImageWithPlaceholderWhileLoadingProps { src: string @@ -15,18 +16,51 @@ interface ImageWithPlaceholderWhileLoadingProps { placeholderIconColor?: string } -const useStyles = createStyles((theme, props: ImageWithPlaceholderWhileLoadingProps) => ({ - placeholder: { - width: props.placeholderWidth ?? 400, - height: props.placeholderHeight ?? 600, - maxWidth: "100%", - color: props.placeholderIconColor ?? theme.fn.variant({ color: theme.primaryColor, variant: "subtle" }).color, - backgroundColor: props.placeholderBackgroundColor ?? (theme.colorScheme === "dark" ? theme.colors.dark[5] : theme.colors.gray[1]), - }, -})) +const useStyles = tss + .withParams<{ + theme: MantineTheme + placeholderWidth?: number + placeholderHeight?: number + placeholderBackgroundColor?: string + placeholderIconColor?: string + }>() + .create(props => ({ + placeholder: { + width: props.placeholderWidth ?? 400, + height: props.placeholderHeight ?? 600, + maxWidth: "100%", + color: + props.placeholderIconColor ?? + props.theme.fn.variant({ + color: props.theme.primaryColor, + variant: "subtle", + }).color, + backgroundColor: + props.placeholderBackgroundColor ?? + (props.theme.colorScheme === "dark" ? props.theme.colors.dark[5] : props.theme.colors.gray[1]), + }, + })) -export function ImageWithPlaceholderWhileLoading(props: ImageWithPlaceholderWhileLoadingProps) { - const { classes } = useStyles(props) +export function ImageWithPlaceholderWhileLoading({ + alt, + height, + placeholderBackgroundColor, + placeholderHeight, + placeholderIconColor, + placeholderIconSize, + placeholderWidth, + src, + title, + width, +}: ImageWithPlaceholderWhileLoadingProps) { + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + placeholderWidth, + placeholderHeight, + placeholderBackgroundColor, + placeholderIconColor, + }) const [loading, setLoading] = useState(true) return ( @@ -35,17 +69,17 @@ export function ImageWithPlaceholderWhileLoading(props: ImageWithPlaceholderWhil
- +
)} {props.alt} setLoading(false)} style={{ display: loading ? "none" : "block" }} /> diff --git a/commafeed-client/src/components/content/Content.tsx b/commafeed-client/src/components/content/Content.tsx index fb3af164..49b68136 100644 --- a/commafeed-client/src/components/content/Content.tsx +++ b/commafeed-client/src/components/content/Content.tsx @@ -1,31 +1,36 @@ -import { Box, createStyles, Mark, TypographyStylesProvider } from "@mantine/core" +import { Box, type MantineTheme, Mark, TypographyStylesProvider, useMantineTheme } from "@mantine/core" import { Constants } from "app/constants" import { calculatePlaceholderSize } from "app/utils" import { ImageWithPlaceholderWhileLoading } from "components/ImageWithPlaceholderWhileLoading" import escapeStringRegexp from "escape-string-regexp" import { type ChildrenNode, Interweave, Matcher, type MatchResponse, type Node, type TransformCallback } from "interweave" import React from "react" +import { tss } from "tss" export interface ContentProps { content: string highlight?: string } -const useStyles = createStyles(theme => ({ - content: { - // break long links or long words - overflowWrap: "anywhere", - "& a": { - color: theme.fn.variant({ color: theme.primaryColor, variant: "subtle" }).color, +const useStyles = tss + .withParams<{ + theme: MantineTheme + }>() + .create(({ theme }) => ({ + content: { + // break long links or long words + overflowWrap: "anywhere", + "& a": { + color: theme.fn.variant({ color: theme.primaryColor, variant: "subtle" }).color, + }, + "& iframe": { + maxWidth: "100%", + }, + "& pre, & code": { + whiteSpace: "pre-wrap", + }, }, - "& iframe": { - maxWidth: "100%", - }, - "& pre, & code": { - whiteSpace: "pre-wrap", - }, - }, -})) + })) const transform: TransformCallback = node => { if (node.tagName === "IMG") { @@ -84,7 +89,10 @@ class HighlightMatcher extends Matcher { // memoize component because Interweave is costly const Content = React.memo((props: ContentProps) => { - const { classes } = useStyles() + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + }) const matchers = props.highlight ? [new HighlightMatcher(props.highlight)] : [] return ( diff --git a/commafeed-client/src/components/content/FeedEntry.tsx b/commafeed-client/src/components/content/FeedEntry.tsx index f3615416..4162eb9c 100644 --- a/commafeed-client/src/components/content/FeedEntry.tsx +++ b/commafeed-client/src/components/content/FeedEntry.tsx @@ -1,10 +1,11 @@ -import { Box, createStyles, Divider, Paper } from "@mantine/core" +import { Box, Divider, type MantineTheme, Paper, useMantineTheme } from "@mantine/core" import { type MantineNumberSize } from "@mantine/styles" import { Constants } from "app/constants" import { type Entry, type ViewMode } from "app/types" import { useViewMode } from "hooks/useViewMode" import React from "react" import { useSwipeable } from "react-swipeable" +import { tss } from "tss" import { FeedEntryBody } from "./FeedEntryBody" import { FeedEntryCompactHeader } from "./FeedEntryCompactHeader" import { FeedEntryContextMenu } from "./FeedEntryContextMenu" @@ -23,69 +24,88 @@ interface FeedEntryProps { onSwipedRight: () => void } -const useStyles = createStyles((theme, props: FeedEntryProps & { viewMode?: ViewMode }) => { - let backgroundColor - if (theme.colorScheme === "dark") { - backgroundColor = props.entry.read ? "inherit" : theme.colors.dark[5] - } else { - backgroundColor = props.entry.read && !props.expanded ? theme.colors.gray[0] : "inherit" - } +const useStyles = tss + .withParams<{ + theme: MantineTheme + read: boolean + expanded: boolean + viewMode: ViewMode + rtl: boolean + showSelectionIndicator: boolean + maxWidth?: number + }>() + .create(({ theme, read, expanded, viewMode, rtl, showSelectionIndicator, maxWidth }) => { + let backgroundColor + if (theme.colorScheme === "dark") { + backgroundColor = read ? "inherit" : theme.colors.dark[5] + } else { + backgroundColor = read && !expanded ? theme.colors.gray[0] : "inherit" + } - let marginY = 10 - if (props.viewMode === "title") { - marginY = 2 - } else if (props.viewMode === "cozy") { - marginY = 6 - } + let marginY = 10 + if (viewMode === "title") { + marginY = 2 + } else if (viewMode === "cozy") { + marginY = 6 + } - let mobileMarginY = 6 - if (props.viewMode === "title") { - mobileMarginY = 2 - } else if (props.viewMode === "cozy") { - mobileMarginY = 4 - } + let mobileMarginY = 6 + if (viewMode === "title") { + mobileMarginY = 2 + } else if (viewMode === "cozy") { + mobileMarginY = 4 + } - let backgroundHoverColor = backgroundColor - if (!props.expanded && !props.entry.read) { - backgroundHoverColor = theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[1] - } + let backgroundHoverColor = backgroundColor + if (!expanded && !read) { + backgroundHoverColor = theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[1] + } - let paperBorderLeftColor - if (props.showSelectionIndicator) { - const borderLeftColor = theme.colorScheme === "dark" ? theme.colors.orange[4] : theme.colors.orange[6] - paperBorderLeftColor = `${borderLeftColor} !important` - } + let paperBorderLeftColor + if (showSelectionIndicator) { + const borderLeftColor = theme.colorScheme === "dark" ? theme.colors.orange[4] : theme.colors.orange[6] + paperBorderLeftColor = `${borderLeftColor} !important` + } - return { - paper: { - backgroundColor, - borderLeftColor: paperBorderLeftColor, - marginTop: marginY, - marginBottom: marginY, - [theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: { - marginTop: mobileMarginY, - marginBottom: mobileMarginY, - }, - "@media (hover: hover)": { - "&:hover": { - backgroundColor: backgroundHoverColor, + return { + paper: { + backgroundColor, + borderLeftColor: paperBorderLeftColor, + marginTop: marginY, + marginBottom: marginY, + [theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: { + marginTop: mobileMarginY, + marginBottom: mobileMarginY, + }, + "@media (hover: hover)": { + "&:hover": { + backgroundColor: backgroundHoverColor, + }, }, }, - }, - headerLink: { - color: "inherit", - textDecoration: "none", - }, - body: { - direction: props.entry.rtl ? "rtl" : "ltr", - maxWidth: props.maxWidth ?? "100%", - }, - } -}) + headerLink: { + color: "inherit", + textDecoration: "none", + }, + body: { + direction: rtl ? "rtl" : "ltr", + maxWidth: maxWidth ?? "100%", + }, + } + }) export function FeedEntry(props: FeedEntryProps) { + const theme = useMantineTheme() const { viewMode } = useViewMode() - const { classes, cx } = useStyles({ ...props, viewMode }) + const { classes, cx } = useStyles({ + theme, + read: props.entry.read, + expanded: props.expanded, + viewMode, + rtl: props.entry.rtl, + showSelectionIndicator: props.showSelectionIndicator, + maxWidth: props.maxWidth, + }) const swipeHandlers = useSwipeable({ onSwipedRight: props.onSwipedRight, diff --git a/commafeed-client/src/components/content/FeedEntryCompactHeader.tsx b/commafeed-client/src/components/content/FeedEntryCompactHeader.tsx index 84403abc..c06fabc2 100644 --- a/commafeed-client/src/components/content/FeedEntryCompactHeader.tsx +++ b/commafeed-client/src/components/content/FeedEntryCompactHeader.tsx @@ -1,7 +1,8 @@ -import { Box, createStyles, Text } from "@mantine/core" +import { Box, type MantineTheme, Text, useMantineTheme } from "@mantine/core" import { type Entry } from "app/types" import { RelativeDate } from "components/RelativeDate" import { OnDesktop } from "components/responsive/OnDesktop" +import { tss } from "tss" import { FeedEntryTitle } from "./FeedEntryTitle" import { FeedFavicon } from "./FeedFavicon" @@ -9,32 +10,42 @@ export interface FeedEntryHeaderProps { entry: Entry } -const useStyles = createStyles((theme, props: FeedEntryHeaderProps) => ({ - wrapper: { - display: "flex", - alignItems: "center", - columnGap: "10px", - }, - title: { - flexGrow: 1, - fontWeight: theme.colorScheme === "light" && !props.entry.read ? "bold" : "inherit", - whiteSpace: "nowrap", - overflow: "hidden", - textOverflow: "ellipsis", - }, - feedName: { - width: "145px", - minWidth: "145px", - whiteSpace: "nowrap", - overflow: "hidden", - textOverflow: "ellipsis", - }, - date: { - whiteSpace: "nowrap", - }, -})) +const useStyles = tss + .withParams<{ + theme: MantineTheme + read: boolean + }>() + .create(({ read, theme }) => ({ + wrapper: { + display: "flex", + alignItems: "center", + columnGap: "10px", + }, + title: { + flexGrow: 1, + fontWeight: theme.colorScheme === "light" && !read ? "bold" : "inherit", + whiteSpace: "nowrap", + overflow: "hidden", + textOverflow: "ellipsis", + }, + feedName: { + width: "145px", + minWidth: "145px", + whiteSpace: "nowrap", + overflow: "hidden", + textOverflow: "ellipsis", + }, + date: { + whiteSpace: "nowrap", + }, + })) + export function FeedEntryCompactHeader(props: FeedEntryHeaderProps) { - const { classes } = useStyles(props) + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + read: props.entry.read, + }) return ( diff --git a/commafeed-client/src/components/content/FeedEntryContextMenu.tsx b/commafeed-client/src/components/content/FeedEntryContextMenu.tsx index 1c82570c..2f9dd9ca 100644 --- a/commafeed-client/src/components/content/FeedEntryContextMenu.tsx +++ b/commafeed-client/src/components/content/FeedEntryContextMenu.tsx @@ -1,5 +1,5 @@ import { Trans } from "@lingui/macro" -import { createStyles, Group } from "@mantine/core" +import { Group, type MantineTheme, useMantineTheme } from "@mantine/core" import { Constants } from "app/constants" import { markEntriesUpToEntry, markEntry, starEntry } from "app/entries/thunks" import { redirectToFeed } from "app/redirect/thunks" @@ -9,26 +9,34 @@ import { truncate } from "app/utils" import { useBrowserExtension } from "hooks/useBrowserExtension" import { Item, Menu, Separator } from "react-contexify" import { TbArrowBarToDown, TbExternalLink, TbEyeCheck, TbEyeOff, TbRss, TbStar, TbStarOff } from "react-icons/tb" +import { tss } from "tss" interface FeedEntryContextMenuProps { entry: Entry } const iconSize = 16 -const useStyles = createStyles(theme => ({ - menu: { - // apply mantine theme from MenuItem.styles.ts - fontSize: theme.fontSizes.sm, - "--contexify-item-color": `${theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black} !important`, - "--contexify-activeItem-color": `${theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black} !important`, - "--contexify-activeItem-bgColor": `${ - theme.colorScheme === "dark" ? theme.fn.rgba(theme.colors.dark[3], 0.35) : theme.colors.gray[1] - } !important`, - }, -})) +const useStyles = tss + .withParams<{ + theme: MantineTheme + }>() + .create(({ theme }) => ({ + menu: { + // apply mantine theme from MenuItem.styles.ts + fontSize: theme.fontSizes.sm, + "--contexify-item-color": `${theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black} !important`, + "--contexify-activeItem-color": `${theme.colorScheme === "dark" ? theme.colors.dark[0] : theme.black} !important`, + "--contexify-activeItem-bgColor": `${ + theme.colorScheme === "dark" ? theme.fn.rgba(theme.colors.dark[3], 0.35) : theme.colors.gray[1] + } !important`, + }, + })) export function FeedEntryContextMenu(props: FeedEntryContextMenuProps) { - const { classes, theme } = useStyles() + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + }) const sourceType = useAppSelector(state => state.entries.source.type) const dispatch = useAppDispatch() const { openLinkInBackgroundTab } = useBrowserExtension() diff --git a/commafeed-client/src/components/content/FeedEntryHeader.tsx b/commafeed-client/src/components/content/FeedEntryHeader.tsx index 787196aa..0e66bf8d 100644 --- a/commafeed-client/src/components/content/FeedEntryHeader.tsx +++ b/commafeed-client/src/components/content/FeedEntryHeader.tsx @@ -1,6 +1,7 @@ -import { Box, createStyles, Space, Text } from "@mantine/core" +import { Box, type MantineTheme, Space, Text, useMantineTheme } from "@mantine/core" import { type Entry } from "app/types" import { RelativeDate } from "components/RelativeDate" +import { tss } from "tss" import { FeedEntryTitle } from "./FeedEntryTitle" import { FeedFavicon } from "./FeedFavicon" @@ -9,18 +10,28 @@ export interface FeedEntryHeaderProps { expanded: boolean } -const useStyles = createStyles((theme, props: FeedEntryHeaderProps) => ({ - headerText: { - fontWeight: theme.colorScheme === "light" && !props.entry.read ? "bold" : "inherit", - }, - headerSubtext: { - display: "flex", - alignItems: "center", - fontSize: "90%", - }, -})) +const useStyles = tss + .withParams<{ + theme: MantineTheme + read: boolean + }>() + .create(({ theme, read }) => ({ + headerText: { + fontWeight: theme.colorScheme === "light" && !read ? "bold" : "inherit", + }, + headerSubtext: { + display: "flex", + alignItems: "center", + fontSize: "90%", + }, + })) + export function FeedEntryHeader(props: FeedEntryHeaderProps) { - const { classes } = useStyles(props) + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + read: props.entry.read, + }) return ( diff --git a/commafeed-client/src/components/content/ShareButtons.tsx b/commafeed-client/src/components/content/ShareButtons.tsx index 388ad88f..65e9e70e 100644 --- a/commafeed-client/src/components/content/ShareButtons.tsx +++ b/commafeed-client/src/components/content/ShareButtons.tsx @@ -1,21 +1,31 @@ -import { ActionIcon, Box, createStyles, SimpleGrid } from "@mantine/core" +import { ActionIcon, Box, type MantineTheme, SimpleGrid, useMantineTheme } from "@mantine/core" import { Constants } from "app/constants" import { useAppSelector } from "app/store" import { type SharingSettings } from "app/types" import { type IconType } from "react-icons" +import { tss } from "tss" type Color = `#${string}` -const useStyles = createStyles((theme, props: { color: Color }) => ({ - socialIcon: { - color: props.color, - backgroundColor: theme.colorScheme === "dark" ? theme.colors.gray[2] : "white", - borderRadius: "50%", - }, -})) +const useStyles = tss + .withParams<{ + theme: MantineTheme + color: Color + }>() + .create(({ theme, color }) => ({ + socialIcon: { + color, + backgroundColor: theme.colorScheme === "dark" ? theme.colors.gray[2] : "white", + borderRadius: "50%", + }, + })) function ShareButton({ url, icon, color }: { url: string; icon: IconType; color: Color }) { - const { classes } = useStyles({ color }) + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + color, + }) const onClick = (e: React.MouseEvent) => { e.preventDefault() diff --git a/commafeed-client/src/components/sidebar/TreeNode.tsx b/commafeed-client/src/components/sidebar/TreeNode.tsx index b0a0ef31..c44057dc 100644 --- a/commafeed-client/src/components/sidebar/TreeNode.tsx +++ b/commafeed-client/src/components/sidebar/TreeNode.tsx @@ -1,6 +1,7 @@ -import { Box, Center, createStyles } from "@mantine/core" +import { Box, Center, type MantineTheme, useMantineTheme } from "@mantine/core" import { FeedFavicon } from "components/content/FeedFavicon" import React, { type ReactNode } from "react" +import { tss } from "tss" import { UnreadCount } from "./UnreadCount" interface TreeNodeProps { @@ -16,40 +17,57 @@ interface TreeNodeProps { onIconClick?: (e: React.MouseEvent, id: string) => void } -const useStyles = createStyles((theme, props: TreeNodeProps) => { - let backgroundColor = "inherit" - if (props.selected) backgroundColor = theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3] +const useStyles = tss + .withParams<{ + theme: MantineTheme + selected: boolean + hasError: boolean + hasUnread: boolean + }>() + .create(({ theme, selected, hasError, hasUnread }) => { + let backgroundColor = "inherit" + if (selected) backgroundColor = theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3] - let color - if (props.hasError) color = theme.colors.red[6] - else if (theme.colorScheme === "dark") color = props.unread > 0 ? theme.colors.dark[0] : theme.colors.dark[3] - else color = props.unread > 0 ? theme.black : theme.colors.gray[6] + let color + if (hasError) { + color = theme.colors.red[6] + } else if (theme.colorScheme === "dark") { + color = hasUnread ? theme.colors.dark[0] : theme.colors.dark[3] + } else { + color = hasUnread ? theme.black : theme.colors.gray[6] + } - return { - node: { - display: "flex", - alignItems: "center", - cursor: "pointer", - color, - backgroundColor, - "&:hover": { - backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0], + return { + node: { + display: "flex", + alignItems: "center", + cursor: "pointer", + color, + backgroundColor, + "&:hover": { + backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[6] : theme.colors.gray[0], + }, }, - }, - nodeText: { - flexGrow: 1, - whiteSpace: "nowrap", - overflow: "hidden", - textOverflow: "ellipsis", - }, - } -}) + nodeText: { + flexGrow: 1, + whiteSpace: "nowrap", + overflow: "hidden", + textOverflow: "ellipsis", + }, + } + }) export function TreeNode(props: TreeNodeProps) { - const { classes } = useStyles(props) + const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + selected: props.selected, + hasError: props.hasError, + hasUnread: props.unread > 0, + }) return ( props.onClick(e, props.id)}> - props.onIconClick && props.onIconClick(e, props.id)}> + props.onIconClick?.(e, props.id)}>
{typeof props.icon === "string" ? : props.icon}
{props.name} diff --git a/commafeed-client/src/components/sidebar/UnreadCount.tsx b/commafeed-client/src/components/sidebar/UnreadCount.tsx index ffcf7448..880727dd 100644 --- a/commafeed-client/src/components/sidebar/UnreadCount.tsx +++ b/commafeed-client/src/components/sidebar/UnreadCount.tsx @@ -1,6 +1,7 @@ -import { Badge, createStyles, Tooltip } from "@mantine/core" +import { Badge, Tooltip } from "@mantine/core" +import { tss } from "tss" -const useStyles = createStyles(() => ({ +const useStyles = tss.create(() => ({ badge: { width: "3.2rem", // for some reason, mantine Badge has "cursor: 'default'" diff --git a/commafeed-client/src/pages/ErrorPage.tsx b/commafeed-client/src/pages/ErrorPage.tsx index 0d1bbf1e..98e13910 100644 --- a/commafeed-client/src/pages/ErrorPage.tsx +++ b/commafeed-client/src/pages/ErrorPage.tsx @@ -1,38 +1,44 @@ import { Trans } from "@lingui/macro" -import { Box, Button, Container, createStyles, Group, Text, Title } from "@mantine/core" +import { Box, Button, Container, Group, type MantineTheme, Text, Title, useMantineTheme } from "@mantine/core" import { TbRefresh } from "react-icons/tb" +import { tss } from "tss" import { PageTitle } from "./PageTitle" -const useStyles = createStyles(theme => ({ - root: { - paddingTop: 80, - }, +const useStyles = tss + .withParams<{ + theme: MantineTheme + }>() + .create(({ theme }) => ({ + root: { + paddingTop: 80, + }, - label: { - textAlign: "center", - fontWeight: "bold", - fontSize: 120, - lineHeight: 1, - marginBottom: `calc(${theme.spacing.xl} * 1.5)`, - color: theme.colors[theme.primaryColor][3], - }, + label: { + textAlign: "center", + fontWeight: "bold", + fontSize: 120, + lineHeight: 1, + marginBottom: `calc(${theme.spacing.xl} * 1.5)`, + color: theme.colors[theme.primaryColor][3], + }, - title: { - textAlign: "center", - fontWeight: "bold", - fontSize: 32, - }, + title: { + textAlign: "center", + fontWeight: "bold", + fontSize: 32, + }, - description: { - maxWidth: 540, - margin: "auto", - marginTop: theme.spacing.xl, - marginBottom: `calc(${theme.spacing.xl} * 1.5)`, - }, -})) + description: { + maxWidth: 540, + margin: "auto", + marginTop: theme.spacing.xl, + marginBottom: `calc(${theme.spacing.xl} * 1.5)`, + }, + })) export function ErrorPage(props: { error: Error }) { - const { classes } = useStyles() + const theme = useMantineTheme() + const { classes } = useStyles({ theme }) return (
diff --git a/commafeed-client/src/pages/app/AboutPage.tsx b/commafeed-client/src/pages/app/AboutPage.tsx index dd719bdc..a91e77b7 100644 --- a/commafeed-client/src/pages/app/AboutPage.tsx +++ b/commafeed-client/src/pages/app/AboutPage.tsx @@ -1,5 +1,5 @@ import { t, Trans } from "@lingui/macro" -import { Anchor, Box, Container, createStyles, List, NativeSelect, SimpleGrid, Title } from "@mantine/core" +import { Anchor, Box, Container, List, NativeSelect, SimpleGrid, Title } from "@mantine/core" import { Constants } from "app/constants" import { redirectToApiDocumentation } from "app/redirect/thunks" import { useAppDispatch, useAppSelector } from "app/store" @@ -8,8 +8,9 @@ import { KeyboardShortcutsHelp } from "components/KeyboardShortcutsHelp" import { useBrowserExtension } from "hooks/useBrowserExtension" import React, { useState } from "react" import { TbHelp, TbKeyboard, TbPuzzle, TbRocket } from "react-icons/tb" +import { tss } from "tss" -const useStyles = createStyles(() => ({ +const useStyles = tss.create(() => ({ sectionTitle: { display: "flex", alignItems: "center", diff --git a/commafeed-client/src/pages/app/FeedEntriesPage.tsx b/commafeed-client/src/pages/app/FeedEntriesPage.tsx index 2c81795b..22c64837 100644 --- a/commafeed-client/src/pages/app/FeedEntriesPage.tsx +++ b/commafeed-client/src/pages/app/FeedEntriesPage.tsx @@ -1,5 +1,5 @@ import { Trans } from "@lingui/macro" -import { ActionIcon, Box, Center, createStyles, Divider, Group, Title, useMantineTheme } from "@mantine/core" +import { ActionIcon, Box, Center, Divider, Group, Title, useMantineTheme } from "@mantine/core" import { useViewportSize } from "@mantine/hooks" import { Constants } from "app/constants" import { type EntrySourceType } from "app/entries/slice" @@ -11,6 +11,7 @@ import { FeedEntries } from "components/content/FeedEntries" import { useEffect } from "react" import { TbEdit } from "react-icons/tb" import { useLocation, useParams } from "react-router-dom" +import { tss } from "tss" function NoSubscriptionHelp() { return ( @@ -28,7 +29,7 @@ interface FeedEntriesPageProps { sourceType: EntrySourceType } -const useStyles = createStyles(() => ({ +const useStyles = tss.create(() => ({ sourceWebsiteLink: { color: "inherit", textDecoration: "none", diff --git a/commafeed-client/src/pages/app/Layout.tsx b/commafeed-client/src/pages/app/Layout.tsx index 3a6d57dc..795bec85 100644 --- a/commafeed-client/src/pages/app/Layout.tsx +++ b/commafeed-client/src/pages/app/Layout.tsx @@ -4,10 +4,10 @@ import { Box, Burger, Center, - createStyles, DEFAULT_THEME, Group, Header, + type MantineTheme, Navbar, ScrollArea, Title, @@ -32,6 +32,7 @@ import { Resizable } from "re-resizable" import { type ReactNode, Suspense, useEffect } from "react" import { TbPlus } from "react-icons/tb" import { Outlet } from "react-router-dom" +import { tss } from "tss" interface LayoutProps { sidebar: ReactNode @@ -42,40 +43,45 @@ interface LayoutProps { const sidebarPadding = DEFAULT_THEME.spacing.xs const sidebarRightBorderWidth = "1px" -const useStyles = createStyles((theme, props: LayoutProps) => ({ - sidebar: { - "& .mantine-ScrollArea-scrollbar[data-orientation='horizontal']": { - display: "none", +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(${props.sidebarWidth}px - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`, - [theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: { - maxWidth: `calc(100vw - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`, + sidebarContentResizeWrapper: { + padding: sidebarPadding, + minHeight: `calc(100vh - ${Constants.layout.headerHeight}px)`, }, - }, - mainContentWrapper: { - paddingTop: Constants.layout.headerHeight, - paddingLeft: props.sidebarWidth, - paddingRight: 0, - paddingBottom: 0, - [theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: { - paddingLeft: 0, + sidebarContent: { + maxWidth: `calc(${sidebarWidth}px - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`, + [theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: { + maxWidth: `calc(100vw - ${sidebarPadding} * 2 - ${sidebarRightBorderWidth})`, + }, }, - }, - mainContent: { - maxWidth: `calc(100vw - ${props.sidebarWidth}px)`, - padding: theme.spacing.md, - [theme.fn.smallerThan(Constants.layout.mobileBreakpoint)]: { - maxWidth: "100vw", - padding: "6px", + 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() @@ -90,8 +96,11 @@ function LogoAndTitle() { } export default function Layout(props: LayoutProps) { - const { classes } = useStyles(props) const theme = useMantineTheme() + const { classes } = useStyles({ + theme, + sidebarWidth: props.sidebarWidth, + }) const { loading } = useAppLoading() const mobile = useMobile() const mobileMenuOpen = useAppSelector(state => state.tree.mobileMenuOpen) diff --git a/commafeed-client/src/tss.ts b/commafeed-client/src/tss.ts new file mode 100644 index 00000000..2b6cfbe0 --- /dev/null +++ b/commafeed-client/src/tss.ts @@ -0,0 +1,11 @@ +import { createTss } from "tss-react" + +const useContext = () => { + // return anything here that will be accessible in tss.create() + // we don't need anything right now + return {} +} + +export const { tss } = createTss({ useContext }) + +export const useStyles = tss.create({})