From a9a41b3877a55412575453db4fa294436ca7d6e6 Mon Sep 17 00:00:00 2001
From: EthanHealy01 <80844253+EthanHealy01@users.noreply.github.com>
Date: Fri, 25 Jul 2025 12:27:30 +0100
Subject: [PATCH] V2: Design Navbar (#4017)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Description of Changes
- Changed the navbar styling to include all the icons that were on our
figma design
- Added a new link to our index.html to include the MUI symbols.
- I chose to keep the automate and read icons the same as they were
already because I feel as though they make more sense
```
```
---
figma vs app dark
figma vs app light
## Checklist
### General
- [x] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [x] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [x] I have performed a self-review of my own code
- [x] My changes generate no new warnings
### Documentation
- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)
### UI Changes (if applicable)
- [x] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)
### Testing (if applicable)
- [x] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
---
frontend/package-lock.json | 7 +
frontend/package.json | 1 +
.../src/components/shared/QuickAccessBar.css | 179 ++++++++++
.../src/components/shared/QuickAccessBar.tsx | 326 +++++++++++++++---
frontend/src/global.d.ts | 1 +
frontend/src/hooks/useIsOverflowing.ts | 73 ++++
frontend/src/index.css | 6 +
frontend/src/pages/HomePage.tsx | 12 +-
frontend/src/styles/theme.css | 106 ++++--
9 files changed, 632 insertions(+), 79 deletions(-)
create mode 100644 frontend/src/components/shared/QuickAccessBar.css
create mode 100644 frontend/src/hooks/useIsOverflowing.ts
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 (
+ <>
+