mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-06 20:45:30 +00:00
use rem styling, make navbar scrollable on overflow, extrapolate styling to be re-usable and remove redundant nav item colors, rely on tailwind theme instead
This commit is contained in:
parent
7d09bf9e45
commit
3a76d13097
@ -3,7 +3,6 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,700,0,0" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
|
7
frontend/package-lock.json
generated
7
frontend/package-lock.json
generated
@ -27,6 +27,7 @@
|
|||||||
"i18next-browser-languagedetector": "^8.1.0",
|
"i18next-browser-languagedetector": "^8.1.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
|
"material-symbols": "^0.33.0",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^3.11.174",
|
"pdfjs-dist": "^3.11.174",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
@ -4175,6 +4176,12 @@
|
|||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/material-symbols": {
|
||||||
|
"version": "0.33.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/material-symbols/-/material-symbols-0.33.0.tgz",
|
||||||
|
"integrity": "sha512-t9/Gz+14fClRgN7oVOt5CBuwsjFLxSNP9BRDyMrI5el3IZNvoD94IDGJha0YYivyAow24rCS0WOkAv4Dp+YjNg==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
"i18next-browser-languagedetector": "^8.1.0",
|
"i18next-browser-languagedetector": "^8.1.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
|
"material-symbols": "^0.33.0",
|
||||||
"pdf-lib": "^1.17.1",
|
"pdf-lib": "^1.17.1",
|
||||||
"pdfjs-dist": "^3.11.174",
|
"pdfjs-dist": "^3.11.174",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
|
@ -12,16 +12,38 @@
|
|||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fallbackDivider {
|
/* Scrollable navbar styling - scrollbars only show when scrolling */
|
||||||
width: 60px;
|
.quick-access-bar {
|
||||||
height: 1px;
|
overflow-x: auto;
|
||||||
background-color: var(--color-gray-300);
|
overflow-y: hidden;
|
||||||
margin: 8px 0;
|
scrollbar-gutter: stable both-edges;
|
||||||
border-radius: 1px;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mantineDivider {
|
/* Hide scrollbar by default, show on scroll (Webkit browsers - Chrome, Safari, Edge) */
|
||||||
width: 60px;
|
.quick-access-bar::-webkit-scrollbar {
|
||||||
margin: 8px 0;
|
width: 8px;
|
||||||
border-color: var(--color-gray-300);
|
height: 8px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-bar:hover::-webkit-scrollbar,
|
||||||
|
.quick-access-bar:active::-webkit-scrollbar,
|
||||||
|
.quick-access-bar:focus::-webkit-scrollbar {
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-bar::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-access-bar::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox scrollbar styling */
|
||||||
|
.quick-access-bar {
|
||||||
|
scrollbar-width: auto;
|
||||||
|
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
||||||
}
|
}
|
@ -26,45 +26,39 @@ interface ButtonConfig {
|
|||||||
name: string;
|
name: string;
|
||||||
icon: React.ReactNode;
|
icon: React.ReactNode;
|
||||||
tooltip: string;
|
tooltip: string;
|
||||||
color: string;
|
|
||||||
isRound?: boolean;
|
isRound?: boolean;
|
||||||
size?: 'sm' | 'md' | 'lg' | 'xl';
|
size?: 'sm' | 'md' | 'lg' | 'xl';
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const actionIconStyle = {
|
||||||
|
backgroundColor: 'var(--icon-user-bg)',
|
||||||
|
color: 'var(--icon-user-color)',
|
||||||
|
borderRadius: '50%',
|
||||||
|
width: '1.5rem',
|
||||||
|
height: '1.5rem',
|
||||||
|
};
|
||||||
|
|
||||||
function NavHeader() {
|
function NavHeader() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row items-center justify-center mb-0">
|
<div className="flex flex-row items-center justify-center mb-0" style={{ gap: '0.5rem' }}>
|
||||||
<Tooltip label="User Profile" position="right">
|
<Tooltip label="User Profile" position="right">
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size="md"
|
size="md"
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
style={{
|
style={actionIconStyle}
|
||||||
backgroundColor: 'var(--icon-user-bg)',
|
|
||||||
color: 'var(--icon-user-color)',
|
|
||||||
borderRadius: '50%',
|
|
||||||
width: '24px',
|
|
||||||
height: '24px',
|
|
||||||
marginRight: '8px'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<PersonIcon sx={{ fontSize: 16 }} />
|
<PersonIcon sx={{ fontSize: "1rem" }} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip label="Notifications" position="right">
|
<Tooltip label="Notifications" position="right">
|
||||||
<ActionIcon
|
<ActionIcon
|
||||||
size="md"
|
size="md"
|
||||||
variant="subtle"
|
variant="subtle"
|
||||||
style={{
|
style={actionIconStyle}
|
||||||
backgroundColor: 'var(--icon-notifications-bg)',
|
|
||||||
color: 'var(--icon-notifications-color)',
|
|
||||||
borderRadius: '50%',
|
|
||||||
width: '24px',
|
|
||||||
height: '24px'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<NotificationsIcon sx={{ fontSize: 16 }} />
|
<NotificationsIcon sx={{ fontSize: "1rem" }} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
@ -72,7 +66,7 @@ function NavHeader() {
|
|||||||
<Divider
|
<Divider
|
||||||
size="xs"
|
size="xs"
|
||||||
style={{
|
style={{
|
||||||
width: '60px',
|
width: '3.75rem',
|
||||||
borderColor: 'var(--color-gray-300)'
|
borderColor: 'var(--color-gray-300)'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -98,8 +92,8 @@ const QuickAccessBar = ({
|
|||||||
name: 'All Tools',
|
name: 'All Tools',
|
||||||
icon: <AppsIcon sx={{ fontSize: 26 }} />,
|
icon: <AppsIcon sx={{ fontSize: 26 }} />,
|
||||||
tooltip: 'View all available tools',
|
tooltip: 'View all available tools',
|
||||||
color: '#1E88E5',
|
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
|
isRound: false,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveButton('tools');
|
setActiveButton('tools');
|
||||||
onReaderToggle();
|
onReaderToggle();
|
||||||
@ -111,8 +105,8 @@ const QuickAccessBar = ({
|
|||||||
name: 'Read',
|
name: 'Read',
|
||||||
icon: <MenuBookIcon sx={{ fontSize: 20 }} />,
|
icon: <MenuBookIcon sx={{ fontSize: 20 }} />,
|
||||||
tooltip: 'Read documents',
|
tooltip: 'Read documents',
|
||||||
color: '#4CAF50',
|
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
|
isRound: false,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setActiveButton('read');
|
setActiveButton('read');
|
||||||
onReaderToggle();
|
onReaderToggle();
|
||||||
@ -122,12 +116,12 @@ const QuickAccessBar = ({
|
|||||||
id: 'sign',
|
id: 'sign',
|
||||||
name: 'Sign',
|
name: 'Sign',
|
||||||
icon:
|
icon:
|
||||||
<span className="material-symbols-outlined" style={{ fontSize: 20 }}>
|
<span className="material-symbols-rounded" style={{ fontSize: 20 }}>
|
||||||
signature
|
signature
|
||||||
</span>,
|
</span>,
|
||||||
tooltip: 'Sign your document',
|
tooltip: 'Sign your document',
|
||||||
color: '#3BA99C',
|
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
|
isRound: false,
|
||||||
onClick: () => setActiveButton('sign')
|
onClick: () => setActiveButton('sign')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -135,8 +129,8 @@ const QuickAccessBar = ({
|
|||||||
name: 'Automate',
|
name: 'Automate',
|
||||||
icon: <AutoAwesomeIcon sx={{ fontSize: 20 }} />,
|
icon: <AutoAwesomeIcon sx={{ fontSize: 20 }} />,
|
||||||
tooltip: 'Automate workflows',
|
tooltip: 'Automate workflows',
|
||||||
color: '#A576E3',
|
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
|
isRound: false,
|
||||||
onClick: () => setActiveButton('automate')
|
onClick: () => setActiveButton('automate')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -144,34 +138,18 @@ const QuickAccessBar = ({
|
|||||||
name: 'Files',
|
name: 'Files',
|
||||||
icon: <FolderIcon sx={{ fontSize: 20 }} />,
|
icon: <FolderIcon sx={{ fontSize: 20 }} />,
|
||||||
tooltip: 'Manage files',
|
tooltip: 'Manage files',
|
||||||
color: '', // the round icons are blue always, this logic lives in getButtonStyle
|
|
||||||
isRound: true,
|
isRound: true,
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
onClick: () => setActiveButton('files')
|
onClick: () => setActiveButton('files')
|
||||||
},
|
},
|
||||||
/* Access isn't going to be available yet */
|
|
||||||
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
id: 'access',
|
|
||||||
name: 'Access',
|
|
||||||
icon: <GroupIcon sx={{ fontSize: 20 }} />,
|
|
||||||
tooltip: 'Manage access and permissions',
|
|
||||||
color: '#00BCD4',
|
|
||||||
isRound: true,
|
|
||||||
size: 'lg',
|
|
||||||
onClick: () => setActiveButton('access')
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
id: 'activity',
|
id: 'activity',
|
||||||
name: 'Activity',
|
name: 'Activity',
|
||||||
icon:
|
icon:
|
||||||
<span className="material-symbols-outlined" style={{ fontSize: 20 }}>
|
<span className="material-symbols-rounded" style={{ fontSize: 20 }}>
|
||||||
vital_signs
|
vital_signs
|
||||||
</span>,
|
</span>,
|
||||||
tooltip: 'View activity and analytics',
|
tooltip: 'View activity and analytics',
|
||||||
color: '',
|
|
||||||
isRound: true,
|
isRound: true,
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
onClick: () => setActiveButton('activity')
|
onClick: () => setActiveButton('activity')
|
||||||
@ -181,7 +159,6 @@ const QuickAccessBar = ({
|
|||||||
name: 'Config',
|
name: 'Config',
|
||||||
icon: <SettingsIcon sx={{ fontSize: 16 }} />,
|
icon: <SettingsIcon sx={{ fontSize: 16 }} />,
|
||||||
tooltip: 'Configure settings',
|
tooltip: 'Configure settings',
|
||||||
color: '#9CA3AF',
|
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setConfigModalOpen(true);
|
setConfigModalOpen(true);
|
||||||
@ -189,6 +166,13 @@ const QuickAccessBar = ({
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const ROUND_BORDER_RADIUS = '50%';
|
||||||
|
const NOT_ROUND_BORDER_RADIUS = '8px';
|
||||||
|
|
||||||
|
const getBorderRadius = (config: ButtonConfig): string => {
|
||||||
|
return config.isRound ? ROUND_BORDER_RADIUS : NOT_ROUND_BORDER_RADIUS;
|
||||||
|
};
|
||||||
|
|
||||||
const getButtonStyle = (config: ButtonConfig) => {
|
const getButtonStyle = (config: ButtonConfig) => {
|
||||||
const isActive = activeButton === config.id;
|
const isActive = activeButton === config.id;
|
||||||
|
|
||||||
@ -199,7 +183,7 @@ const QuickAccessBar = ({
|
|||||||
backgroundColor: 'var(--icon-tools-bg)',
|
backgroundColor: 'var(--icon-tools-bg)',
|
||||||
color: 'var(--icon-tools-color)',
|
color: 'var(--icon-tools-color)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: config.isRound ? '50%' : '8px',
|
borderRadius: getBorderRadius(config),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (config.id === 'read') {
|
if (config.id === 'read') {
|
||||||
@ -207,7 +191,7 @@ const QuickAccessBar = ({
|
|||||||
backgroundColor: 'var(--icon-read-bg)',
|
backgroundColor: 'var(--icon-read-bg)',
|
||||||
color: 'var(--icon-read-color)',
|
color: 'var(--icon-read-color)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: config.isRound ? '50%' : '8px',
|
borderRadius: getBorderRadius(config),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (config.id === 'sign') {
|
if (config.id === 'sign') {
|
||||||
@ -215,7 +199,7 @@ const QuickAccessBar = ({
|
|||||||
backgroundColor: 'var(--icon-sign-bg)',
|
backgroundColor: 'var(--icon-sign-bg)',
|
||||||
color: 'var(--icon-sign-color)',
|
color: 'var(--icon-sign-color)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: config.isRound ? '50%' : '8px',
|
borderRadius: getBorderRadius(config),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (config.id === 'automate') {
|
if (config.id === 'automate') {
|
||||||
@ -223,21 +207,21 @@ const QuickAccessBar = ({
|
|||||||
backgroundColor: 'var(--icon-automate-bg)',
|
backgroundColor: 'var(--icon-automate-bg)',
|
||||||
color: 'var(--icon-automate-color)',
|
color: 'var(--icon-automate-color)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: config.isRound ? '50%' : '8px',
|
borderRadius: getBorderRadius(config),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (config.id === 'files') {
|
if (config.id === 'files') {
|
||||||
return {
|
return {
|
||||||
backgroundColor: 'var(--icon-files-bg)',
|
backgroundColor: 'var(--icon-files-bg)',
|
||||||
color: 'var(--icon-files-color)',
|
color: 'var(--icon-files-color)',
|
||||||
borderRadius: '50%',
|
borderRadius: ROUND_BORDER_RADIUS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (config.id === 'activity') {
|
if (config.id === 'activity') {
|
||||||
return {
|
return {
|
||||||
backgroundColor: 'var(--icon-activity-bg)',
|
backgroundColor: 'var(--icon-activity-bg)',
|
||||||
color: 'var(--icon-activity-color)',
|
color: 'var(--icon-activity-color)',
|
||||||
borderRadius: '50%',
|
borderRadius: ROUND_BORDER_RADIUS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (config.id === 'config') {
|
if (config.id === 'config') {
|
||||||
@ -245,7 +229,7 @@ const QuickAccessBar = ({
|
|||||||
backgroundColor: 'var(--icon-config-bg)',
|
backgroundColor: 'var(--icon-config-bg)',
|
||||||
color: 'var(--icon-config-color)',
|
color: 'var(--icon-config-color)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: config.isRound ? '50%' : '8px',
|
borderRadius: getBorderRadius(config),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,15 +239,15 @@ const QuickAccessBar = ({
|
|||||||
backgroundColor: 'var(--icon-inactive-bg)',
|
backgroundColor: 'var(--icon-inactive-bg)',
|
||||||
color: 'var(--icon-inactive-color)',
|
color: 'var(--icon-inactive-color)',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
borderRadius: config.isRound ? '50%' : '8px',
|
borderRadius: getBorderRadius(config),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTextStyle = (config: ButtonConfig) => {
|
const getTextStyle = (config: ButtonConfig) => {
|
||||||
const isActive = activeButton === config.id;
|
const isActive = activeButton === config.id;
|
||||||
return {
|
return {
|
||||||
marginTop: '12px',
|
marginTop: '0.75rem',
|
||||||
fontSize: '12px',
|
fontSize: '0.75rem',
|
||||||
color: isActive ? 'var(--text-primary)' : 'var(--color-gray-700)',
|
color: isActive ? 'var(--text-primary)' : 'var(--color-gray-700)',
|
||||||
fontWeight: isActive ? 'bold' : 'normal',
|
fontWeight: isActive ? 'bold' : 'normal',
|
||||||
textRendering: 'optimizeLegibility' as const,
|
textRendering: 'optimizeLegibility' as const,
|
||||||
@ -273,13 +257,19 @@ const QuickAccessBar = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`h-screen flex flex-col w-20 ${isRainbowMode ? rainbowStyles.rainbowPaper : ''}`}
|
className={`h-screen flex flex-col w-20 quick-access-bar ${isRainbowMode ? rainbowStyles.rainbowPaper : ''}`}
|
||||||
style={{
|
style={{
|
||||||
padding: '1rem 0.5rem',
|
padding: '1rem 0.5rem',
|
||||||
backgroundColor: 'var(--bg-muted)',
|
backgroundColor: 'var(--bg-muted)',
|
||||||
width: '80px',
|
width: '5rem',
|
||||||
minWidth: '80px',
|
minWidth: '5rem',
|
||||||
maxWidth: '80px'
|
maxWidth: '5rem',
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 10
|
||||||
|
}}
|
||||||
|
onWheel={(e) => {
|
||||||
|
// Prevent the wheel event from bubbling up to parent containers
|
||||||
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack gap="lg" align="center" className="flex-1">
|
<Stack gap="lg" align="center" className="flex-1">
|
||||||
@ -310,7 +300,7 @@ const QuickAccessBar = ({
|
|||||||
<Divider
|
<Divider
|
||||||
size="xs"
|
size="xs"
|
||||||
style={{
|
style={{
|
||||||
width: '60px',
|
width: '3.75rem',
|
||||||
borderColor: 'var(--color-gray-300)'
|
borderColor: 'var(--color-gray-300)'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
@import 'material-symbols/rounded.css';
|
||||||
|
|
||||||
|
.material-symbols-rounded {
|
||||||
|
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user