Add bookmark button to tool page

This commit is contained in:
Yihao Wang
2025-07-14 14:01:54 +12:00
parent a50028e1fb
commit 03d49e384f
5 changed files with 43 additions and 19 deletions

View File

@@ -167,16 +167,16 @@ export default function Hero() {
fontSize={20} fontSize={20}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
toggleBookmarked(option); toggleBookmarked(option.path);
setBookmarkedToolPaths(getBookmarkedToolPaths()); setBookmarkedToolPaths(getBookmarkedToolPaths());
}} }}
color={ color={
isBookmarked(option) isBookmarked(option.path)
? theme.palette.primary.main ? theme.palette.primary.main
: theme.palette.grey[500] : theme.palette.grey[500]
} }
icon={ icon={
isBookmarked(option) isBookmarked(option.path)
? 'mdi:bookmark' ? 'mdi:bookmark'
: 'mdi:bookmark-plus-outline' : 'mdi:bookmark-plus-outline'
} }

View File

@@ -1,4 +1,4 @@
import { Box, Button, styled, useTheme } from '@mui/material'; import { Box, Button, Stack, styled, useTheme } from '@mui/material';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import ToolBreadcrumb from './ToolBreadcrumb'; import ToolBreadcrumb from './ToolBreadcrumb';
import { capitalizeFirstLetter } from '../utils/string'; import { capitalizeFirstLetter } from '../utils/string';
@@ -7,6 +7,7 @@ import { Icon, IconifyIcon } from '@iconify/react';
import { categoriesColors } from '../config/uiConfig'; import { categoriesColors } from '../config/uiConfig';
import { getToolsByCategory } from '@tools/index'; import { getToolsByCategory } from '@tools/index';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { isBookmarked, toggleBookmarked } from '@utils/bookmark';
const StyledButton = styled(Button)(({ theme }) => ({ const StyledButton = styled(Button)(({ theme }) => ({
backgroundColor: 'white', backgroundColor: 'white',
@@ -21,6 +22,7 @@ interface ToolHeaderProps {
description: string; description: string;
icon?: IconifyIcon | string; icon?: IconifyIcon | string;
type: string; type: string;
path: string;
} }
function ToolLinks() { function ToolLinks() {
@@ -80,8 +82,11 @@ export default function ToolHeader({
icon, icon,
title, title,
description, description,
type type,
path
}: ToolHeaderProps) { }: ToolHeaderProps) {
const theme = useTheme();
const [bookmarked, setBookmarked] = useState<boolean>(isBookmarked(path));
return ( return (
<Box my={4}> <Box my={4}>
<ToolBreadcrumb <ToolBreadcrumb
@@ -98,9 +103,24 @@ export default function ToolHeader({
/> />
<Grid mt={1} container spacing={2}> <Grid mt={1} container spacing={2}>
<Grid item xs={12} md={8}> <Grid item xs={12} md={8}>
<Typography mb={2} fontSize={30} color={'primary'}> <Stack direction={'row'} spacing={2} alignItems={'center'}>
{title} <Typography mb={2} fontSize={30} color={'primary'}>
</Typography> {title}
</Typography>
<Icon
fontSize={30}
color={
bookmarked
? theme.palette.primary.main
: theme.palette.grey[500]
}
onClick={(e) => {
toggleBookmarked(path);
setBookmarked(!bookmarked);
}}
icon={bookmarked ? 'mdi:bookmark' : 'mdi:bookmark-plus-outline'}
/>
</Stack>
<Typography fontSize={20}>{description}</Typography> <Typography fontSize={20}>{description}</Typography>
<ToolLinks /> <ToolLinks />
</Grid> </Grid>

View File

@@ -13,12 +13,14 @@ export default function ToolLayout({
title, title,
description, description,
icon, icon,
type type,
path
}: { }: {
title: string; title: string;
description: string; description: string;
icon?: IconifyIcon | string; icon?: IconifyIcon | string;
type: string; type: string;
path: string;
children: ReactNode; children: ReactNode;
}) { }) {
const otherCategoryTools = const otherCategoryTools =
@@ -49,6 +51,7 @@ export default function ToolLayout({
description={description} description={description}
icon={icon} icon={icon}
type={type} type={type}
path={path}
/> />
{children} {children}
<Separator backgroundColor="#5581b5" margin="50px" /> <Separator backgroundColor="#5581b5" margin="50px" />

View File

@@ -74,6 +74,7 @@ export const defineTool = (
description={description} description={description}
icon={icon} icon={icon}
type={basePath} type={basePath}
path={`${basePath}/${path}`}
> >
<Component title={name} longDescription={longDescription} /> <Component title={name} longDescription={longDescription} />
</ToolLayout> </ToolLayout>

View File

@@ -11,30 +11,30 @@ export function getBookmarkedToolPaths(): string[] {
); );
} }
export function isBookmarked(tool: DefinedTool): boolean { export function isBookmarked(toolPath: string): boolean {
return getBookmarkedToolPaths().some((path) => path === tool.path); return getBookmarkedToolPaths().some((path) => path === toolPath);
} }
export function toggleBookmarked(tool: DefinedTool) { export function toggleBookmarked(toolPath: string) {
if (isBookmarked(tool)) { if (isBookmarked(toolPath)) {
unbookmark(tool); unbookmark(toolPath);
} else { } else {
bookmark(tool); bookmark(toolPath);
} }
} }
function bookmark(tool: DefinedTool) { function bookmark(toolPath: string) {
localStorage.setItem( localStorage.setItem(
bookmarkedToolsKey, bookmarkedToolsKey,
[tool.path, ...getBookmarkedToolPaths()].join(',') [toolPath, ...getBookmarkedToolPaths()].join(',')
); );
} }
function unbookmark(tool: DefinedTool) { function unbookmark(toolPath: string) {
localStorage.setItem( localStorage.setItem(
bookmarkedToolsKey, bookmarkedToolsKey,
getBookmarkedToolPaths() getBookmarkedToolPaths()
.filter((path) => path !== tool.path) .filter((path) => path !== toolPath)
.join(',') .join(',')
); );
} }