diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 60c2af7e4..2124a2b1f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,6 +27,7 @@ "i18next-browser-languagedetector": "^8.1.0", "i18next-http-backend": "^3.0.2", "jszip": "^3.10.1", + "material-symbols": "^0.33.0", "pdf-lib": "^1.17.1", "pdfjs-dist": "^3.11.174", "react": "^19.1.0", @@ -4175,6 +4176,12 @@ "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": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index aa5251545..4f7284717 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,7 @@ "i18next-browser-languagedetector": "^8.1.0", "i18next-http-backend": "^3.0.2", "jszip": "^3.10.1", + "material-symbols": "^0.33.0", "pdf-lib": "^1.17.1", "pdfjs-dist": "^3.11.174", "react": "^19.1.0", diff --git a/frontend/src/components/shared/QuickAccessBar.css b/frontend/src/components/shared/QuickAccessBar.css new file mode 100644 index 000000000..b1d22fcc3 --- /dev/null +++ b/frontend/src/components/shared/QuickAccessBar.css @@ -0,0 +1,179 @@ +.activeIconScale { + transform: scale(1.3); + transition: transform 0.2s; + z-index: 1; +} + +.iconContainer { + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; +} + +/* Action icon styles */ +.action-icon-style { + background-color: var(--icon-user-bg); + color: var(--icon-user-color); + border-radius: 50%; + width: 1.5rem; + height: 1.5rem; +} + +/* Main container styles */ +.quick-access-bar-main { + background-color: var(--bg-muted); + width: 5rem; + min-width: 5rem; + max-width: 5rem; + position: relative; + z-index: 10; +} + +/* Rainbow mode container */ +.quick-access-bar-main.rainbow-mode { + background-color: var(--bg-muted); + width: 5rem; + min-width: 5rem; + max-width: 5rem; + position: relative; + z-index: 10; +} + +/* Header padding */ +.quick-access-header { + padding: 1rem 0.5rem 0.5rem 0.5rem; +} + +.nav-header { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + margin-bottom: 0; + gap: 0.5rem; +} + +/* Nav header divider */ +.nav-header-divider { + width: 3.75rem; + border-color: var(--color-gray-300); + margin-top: 0.5rem; + margin-bottom: 1rem; +} + +/* All tools text styles */ +.all-tools-text { + margin-top: 0.75rem; + font-size: 0.75rem; + text-rendering: optimizeLegibility; + font-synthesis: none; +} + +.all-tools-text.active { + color: var(--text-primary); + font-weight: bold; +} + +.all-tools-text.inactive { + color: var(--color-gray-700); + font-weight: normal; +} + +/* Overflow divider */ +.overflow-divider { + width: 3.75rem; + border-color: var(--color-gray-300); + margin: 0 0.5rem; +} + +/* Scrollable content area */ +.quick-access-bar { + overflow-x: auto; + overflow-y: auto; + scrollbar-gutter: stable both-edges; + -webkit-overflow-scrolling: touch; + padding: 0 0.5rem 1rem 0.5rem; +} + +/* Scrollable content container */ +.scrollable-content { + display: flex; + flex-direction: column; + height: 100%; + min-height: 100%; +} + +/* Button text styles */ +.button-text { + margin-top: 0.75rem; + font-size: 0.75rem; + text-rendering: optimizeLegibility; + font-synthesis: none; +} + +.button-text.active { + color: var(--text-primary); + font-weight: bold; +} + +.button-text.inactive { + color: var(--color-gray-700); + font-weight: normal; +} + +/* Content divider */ +.content-divider { + width: 3.75rem; + border-color: var(--color-gray-300); +} + +/* Spacer */ +.spacer { + flex: 1; + margin-top: 1rem; +} + +/* Config button text */ +.config-button-text { + margin-top: 0.75rem; + font-size: 0.75rem; + color: var(--color-gray-700); + font-weight: normal; + text-rendering: optimizeLegibility; + font-synthesis: none; +} + +/* Font size utility */ +.font-size-20 { + font-size: 20px; +} + +/* Hide scrollbar by default, show on scroll (Webkit browsers - Chrome, Safari, Edge) */ +.quick-access-bar::-webkit-scrollbar { + width: 0.5rem; + height: 0.5rem; + 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: 0.25rem; +} + +.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; +} \ No newline at end of file diff --git a/frontend/src/components/shared/QuickAccessBar.tsx b/frontend/src/components/shared/QuickAccessBar.tsx index 45f3b28c7..22a49617e 100644 --- a/frontend/src/components/shared/QuickAccessBar.tsx +++ b/frontend/src/components/shared/QuickAccessBar.tsx @@ -1,11 +1,17 @@ -import React, { useState } from "react"; -import { ActionIcon, Stack, Tooltip } from "@mantine/core"; -import MenuBookIcon from "@mui/icons-material/MenuBook"; -import AppsIcon from "@mui/icons-material/Apps"; -import SettingsIcon from "@mui/icons-material/Settings"; +import React, { useState, useRef } from "react"; +import { ActionIcon, Stack, Tooltip, Divider } from "@mantine/core"; +import MenuBookIcon from "@mui/icons-material/MenuBookRounded"; +import AppsIcon from "@mui/icons-material/AppsRounded"; +import SettingsIcon from "@mui/icons-material/SettingsRounded"; +import AutoAwesomeIcon from "@mui/icons-material/AutoAwesomeRounded"; +import FolderIcon from "@mui/icons-material/FolderRounded"; +import PersonIcon from "@mui/icons-material/PersonRounded"; +import NotificationsIcon from "@mui/icons-material/NotificationsRounded"; import { useRainbowThemeContext } from "./RainbowThemeProvider"; import rainbowStyles from '../../styles/rainbow.module.css'; import AppConfigModal from './AppConfigModal'; +import { useIsOverflowing } from '../../hooks/useIsOverflowing'; +import './QuickAccessBar.css'; interface QuickAccessBarProps { onToolsClick: () => void; @@ -16,6 +22,86 @@ interface QuickAccessBarProps { readerMode: boolean; } +interface ButtonConfig { + id: string; + name: string; + icon: React.ReactNode; + tooltip: string; + isRound?: boolean; + size?: 'sm' | 'md' | 'lg' | 'xl'; + onClick: () => void; +} + +function NavHeader({ + activeButton, + setActiveButton, + onReaderToggle, + onToolsClick +}: { + activeButton: string; + setActiveButton: (id: string) => void; + onReaderToggle: () => void; + onToolsClick: () => void; +}) { + return ( + <> +