From 130ecac2081f42b2078fe773b1714c0fe46df7ae Mon Sep 17 00:00:00 2001 From: NotII <46204250+NotII@users.noreply.github.com> Date: Sun, 26 Oct 2025 18:29:23 +0000 Subject: [PATCH] Add Chromebook compatibility fixes and optimizations Implemented comprehensive Chromebook-specific fixes including viewport adjustments, enhanced touch and keyboard detection, improved scrolling and keyboard navigation hooks, and extensive CSS optimizations for better usability. Updated chat and dashboard interfaces for larger touch targets, better focus management, and responsive layouts. Added documentation in docs/CHROMEBOOK-FIXES.md and new hooks for Chromebook scroll and keyboard handling. --- app/dashboard/admin/page.tsx | 2 +- app/dashboard/admin/status/page.tsx | 2 +- app/dashboard/analytics/loading.tsx | 2 +- app/dashboard/categories/page.tsx | 2 +- app/dashboard/chats/layout.tsx | 3 +- app/dashboard/loading.tsx | 2 +- app/dashboard/page.tsx | 2 +- app/dashboard/products/page.tsx | 34 ++-- app/dashboard/storefront/page.tsx | 2 +- app/globals.css | 148 ++++++++++++++++ app/layout.tsx | 3 +- components/admin/AdminAnalytics.tsx | 2 +- components/analytics/AnalyticsDashboard.tsx | 4 +- .../analytics/AnalyticsDashboardSkeleton.tsx | 2 +- components/analytics/ProfitAnalyticsChart.tsx | 4 +- components/dashboard/ChatDetail.tsx | 65 ++++++- components/dashboard/content.tsx | 2 +- components/dashboard/page-loading.tsx | 2 +- components/layout/sidebar.tsx | 2 +- components/modals/product-modal.tsx | 2 +- components/tables/order-table.tsx | 22 +-- components/tables/product-table.tsx | 15 +- docs/CHROMEBOOK-FIXES.md | 165 ++++++++++++++++++ hooks/use-chromebook-keyboard.tsx | 160 +++++++++++++++++ hooks/use-chromebook-scroll.tsx | 86 +++++++++ hooks/use-mobile.tsx | 17 +- public/git-info.json | 4 +- 27 files changed, 691 insertions(+), 65 deletions(-) create mode 100644 docs/CHROMEBOOK-FIXES.md create mode 100644 hooks/use-chromebook-keyboard.tsx create mode 100644 hooks/use-chromebook-scroll.tsx diff --git a/app/dashboard/admin/page.tsx b/app/dashboard/admin/page.tsx index d3fbe10..8bde25a 100644 --- a/app/dashboard/admin/page.tsx +++ b/app/dashboard/admin/page.tsx @@ -16,7 +16,7 @@ export default function AdminPage() {

Restricted area. Only admin1 can access.

-
+
diff --git a/app/dashboard/admin/status/page.tsx b/app/dashboard/admin/status/page.tsx index 5f26c91..618e143 100644 --- a/app/dashboard/admin/status/page.tsx +++ b/app/dashboard/admin/status/page.tsx @@ -74,7 +74,7 @@ export default async function AdminStatusPage() {

Monitor system health and performance metrics

-
+
{/* Server Status */} diff --git a/app/dashboard/analytics/loading.tsx b/app/dashboard/analytics/loading.tsx index 7dee90c..a2943cb 100644 --- a/app/dashboard/analytics/loading.tsx +++ b/app/dashboard/analytics/loading.tsx @@ -12,7 +12,7 @@ export default function AnalyticsLoading() {
{/* Metrics Cards */} -
+
{[...Array(4)].map((_, i) => ( diff --git a/app/dashboard/categories/page.tsx b/app/dashboard/categories/page.tsx index a7d8f17..0bf0216 100644 --- a/app/dashboard/categories/page.tsx +++ b/app/dashboard/categories/page.tsx @@ -353,7 +353,7 @@ export default function CategoriesPage() {
-
+
{/* Add Category Card - Takes up 2 columns */} diff --git a/app/dashboard/chats/layout.tsx b/app/dashboard/chats/layout.tsx index 51463be..0f8ffc8 100644 --- a/app/dashboard/chats/layout.tsx +++ b/app/dashboard/chats/layout.tsx @@ -8,8 +8,9 @@ export const metadata: Metadata = { export const viewport: Viewport = { width: "device-width", initialScale: 1, - maximumScale: 5, + maximumScale: 3, userScalable: true, + viewportFit: "cover", themeColor: [ { media: "(prefers-color-scheme: dark)", color: "#000000" }, { media: "(prefers-color-scheme: light)", color: "#D53F8C" }, diff --git a/app/dashboard/loading.tsx b/app/dashboard/loading.tsx index 5f9f15a..bb6a1eb 100644 --- a/app/dashboard/loading.tsx +++ b/app/dashboard/loading.tsx @@ -16,7 +16,7 @@ export default function DashboardLoading() {
{/* Order statistics skeletons */} -
+
{[...Array(4)].map((_, i) => ( diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index 932b90d..35d44fa 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -25,7 +25,7 @@ function DashboardContentSkeleton() {
{/* Stats cards skeleton */} -
+
{[...Array(4)].map((_, i) => ( diff --git a/app/dashboard/products/page.tsx b/app/dashboard/products/page.tsx index 6b9c437..bf2237a 100644 --- a/app/dashboard/products/page.tsx +++ b/app/dashboard/products/page.tsx @@ -386,18 +386,18 @@ export default function ProductsPage() { return (
-
+

Products

-
+
setSearchTerm(e.target.value)} /> @@ -412,18 +412,22 @@ export default function ProductsPage() { )}
- - +
+ + +
diff --git a/app/dashboard/storefront/page.tsx b/app/dashboard/storefront/page.tsx index c46ae64..6eb9bda 100644 --- a/app/dashboard/storefront/page.tsx +++ b/app/dashboard/storefront/page.tsx @@ -220,7 +220,7 @@ export default function StorefrontPage() {
-
+
{/* Security Settings */}
diff --git a/app/globals.css b/app/globals.css index f1c9426..9f182d9 100644 --- a/app/globals.css +++ b/app/globals.css @@ -90,6 +90,154 @@ body { background-color: hsl(var(--primary) / 0.9); } + /* Chromebook-specific optimizations */ + @media screen and (max-width: 1366px) and (min-resolution: 1.5dppx) { + /* Chromebook display optimizations */ + .text-sm { + font-size: 0.875rem; + line-height: 1.25rem; + } + + .text-base { + font-size: 1rem; + line-height: 1.5rem; + } + + /* Better touch targets for Chromebooks */ + button, input, textarea, [role="button"], [role="tab"] { + min-height: 48px; + min-width: 48px; + } + + /* Improved spacing for Chromebook screens */ + .space-y-2 > * + * { + margin-top: 0.75rem; + } + + .space-y-4 > * + * { + margin-top: 1.25rem; + } + } + + /* Chromebook touch screen optimizations */ + @media (pointer: coarse) and (hover: none) { + /* Larger touch targets */ + .touch-target { + min-height: 52px; + min-width: 52px; + } + + /* Better spacing for touch interactions */ + .space-y-2 > * + * { + margin-top: 1rem; + } + + /* Improved button padding */ + button { + padding: 0.75rem 1rem; + } + + /* Better input field sizing */ + input, textarea { + padding: 0.875rem; + font-size: 1rem; + } + + /* Enhanced focus states for touch */ + button:focus-visible, input:focus-visible, textarea:focus-visible { + outline: 3px solid hsl(var(--ring)); + outline-offset: 2px; + } + } + + /* Chromebook keyboard navigation improvements */ + @media (hover: hover) and (pointer: fine) { + /* Better hover states for mouse/trackpad */ + button:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + } + + /* Improved focus indicators */ + button:focus-visible, input:focus-visible, textarea:focus-visible { + outline: 2px solid hsl(var(--ring)); + outline-offset: 2px; + box-shadow: 0 0 0 4px hsl(var(--ring) / 0.2); + } + } + + /* Chromebook display scaling fixes */ + @media screen and (min-resolution: 1.5dppx) { + /* Prevent text from being too small on high-DPI displays */ + html { + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; + } + + /* Better font rendering */ + body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + } + + /* Chromebook scrolling improvements */ + .overflow-y-auto { + -webkit-overflow-scrolling: touch; + scroll-behavior: smooth; + /* Better momentum scrolling for Chromebooks */ + overscroll-behavior: contain; + } + + /* Chromebook chat interface optimizations */ + .chat-message { + /* Better message bubble sizing for touch */ + min-height: 44px; + padding: 0.75rem; + } + + /* Chromebook form optimizations */ + .form-input { + /* Better input field sizing for Chromebooks */ + min-height: 48px; + font-size: 1rem; + padding: 0.75rem 1rem; + } + + /* Chromebook button optimizations */ + .btn-chromebook { + min-height: 48px; + min-width: 48px; + padding: 0.75rem 1rem; + font-size: 1rem; + border-radius: 0.5rem; + } + + /* Enhanced keyboard focus indicators for Chromebooks */ + .keyboard-focus { + outline: 3px solid hsl(var(--ring)); + outline-offset: 2px; + box-shadow: 0 0 0 4px hsl(var(--ring) / 0.3); + } + + /* Better focus management for Chromebook keyboard navigation */ + button:focus-visible, + input:focus-visible, + textarea:focus-visible, + [role="button"]:focus-visible, + [role="tab"]:focus-visible { + outline: 3px solid hsl(var(--ring)); + outline-offset: 2px; + box-shadow: 0 0 0 4px hsl(var(--ring) / 0.3); + } + + /* Chromebook-specific focus ring */ + @media (prefers-reduced-motion: no-preference) { + .keyboard-focus { + transition: outline 0.2s ease, box-shadow 0.2s ease; + } + } + .bg-muted { background-color: hsl(var(--muted) / 0.8); } diff --git a/app/layout.tsx b/app/layout.tsx index e0ddcd9..d2017bf 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -55,8 +55,9 @@ export const metadata: Metadata = { export const viewport: Viewport = { width: "device-width", initialScale: 1, - maximumScale: 5, + maximumScale: 3, userScalable: true, + viewportFit: "cover", themeColor: [ { media: "(prefers-color-scheme: dark)", color: "#000000" }, { media: "(prefers-color-scheme: light)", color: "#D53F8C" }, diff --git a/components/admin/AdminAnalytics.tsx b/components/admin/AdminAnalytics.tsx index 49a2832..0fc866a 100644 --- a/components/admin/AdminAnalytics.tsx +++ b/components/admin/AdminAnalytics.tsx @@ -240,7 +240,7 @@ export default function AdminAnalytics() {
-
+
{/* Orders Card */} diff --git a/components/analytics/AnalyticsDashboard.tsx b/components/analytics/AnalyticsDashboard.tsx index 428c9de..a97ed69 100644 --- a/components/analytics/AnalyticsDashboard.tsx +++ b/components/analytics/AnalyticsDashboard.tsx @@ -196,7 +196,7 @@ export default function AnalyticsDashboard({ initialData }: AnalyticsDashboardPr
{/* Key Metrics Cards */} -
+
{isLoading ? ( [...Array(4)].map((_, i) => ( @@ -272,7 +272,7 @@ export default function AnalyticsDashboard({ initialData }: AnalyticsDashboardPr {/* Analytics Tabs */}
- + Revenue diff --git a/components/analytics/AnalyticsDashboardSkeleton.tsx b/components/analytics/AnalyticsDashboardSkeleton.tsx index 20fdefe..ea4e8ad 100644 --- a/components/analytics/AnalyticsDashboardSkeleton.tsx +++ b/components/analytics/AnalyticsDashboardSkeleton.tsx @@ -14,7 +14,7 @@ export default function AnalyticsDashboardSkeleton() { return (
{/* Key Metrics Cards */} -
+
{[...Array(4)].map((_, i) => ( ))} diff --git a/components/analytics/ProfitAnalyticsChart.tsx b/components/analytics/ProfitAnalyticsChart.tsx index 30889cc..eeacd19 100644 --- a/components/analytics/ProfitAnalyticsChart.tsx +++ b/components/analytics/ProfitAnalyticsChart.tsx @@ -77,7 +77,7 @@ export default function ProfitAnalyticsChart({ timeRange, hideNumbers = false }:
{/* Summary Cards Skeleton */} -
+
{[...Array(4)].map((_, i) => ( @@ -197,7 +197,7 @@ export default function ProfitAnalyticsChart({ timeRange, hideNumbers = false }: return (
{/* Summary Cards */} -
+
Revenue (Tracked) diff --git a/components/dashboard/ChatDetail.tsx b/components/dashboard/ChatDetail.tsx index 3637a02..6a9b602 100644 --- a/components/dashboard/ChatDetail.tsx +++ b/components/dashboard/ChatDetail.tsx @@ -15,6 +15,8 @@ import { getCookie, clientFetch } from "@/lib/api"; import { ImageViewerModal } from "@/components/modals/image-viewer-modal"; import BuyerOrderInfo from "./BuyerOrderInfo"; import { useIsTouchDevice } from "@/hooks/use-mobile"; +import { useChromebookScroll, useSmoothScrollToBottom } from "@/hooks/use-chromebook-scroll"; +import { useChromebookKeyboard, useChatFocus } from "@/hooks/use-chromebook-keyboard"; interface Message { _id: string; @@ -100,10 +102,18 @@ export default function ChatDetail({ chatId }: { chatId: string }) { const [selectedAttachmentIndex, setSelectedAttachmentIndex] = useState(null); const seenMessageIdsRef = useRef>(new Set()); const isTouchDevice = useIsTouchDevice(); + const scrollContainerRef = useChromebookScroll(); + const { scrollToBottom, scrollToBottomInstant } = useSmoothScrollToBottom(); + useChromebookKeyboard(); + const { focusMessageInput, focusNextMessage, focusPreviousMessage } = useChatFocus(); // Scroll to bottom utility functions - const scrollToBottom = () => { - messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + const scrollToBottomHandler = () => { + if (scrollContainerRef.current) { + scrollToBottom(scrollContainerRef.current); + } else { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }); + } }; const isNearBottom = () => { @@ -262,7 +272,7 @@ export default function ChatDetail({ chatId }: { chatId: string }) { // Scroll to bottom on initial load setTimeout(() => { - scrollToBottom(); + scrollToBottomHandler(); }, 100); } catch (error) { console.error("Error fetching chat data:", error); @@ -363,13 +373,33 @@ export default function ChatDetail({ chatId }: { chatId: string }) { } else if (e.key === 'Escape') { // Clear the input on Escape setMessage(''); + focusMessageInput(); } else if (e.key === 'ArrowUp' && message === '') { // Load previous message on Arrow Up when input is empty e.preventDefault(); const lastVendorMessage = [...messages].reverse().find(msg => msg.sender === 'vendor'); if (lastVendorMessage) { setMessage(lastVendorMessage.content); + } else { + focusPreviousMessage(); } + } else if (e.key === 'ArrowDown' && message === '') { + // Focus next message + e.preventDefault(); + focusNextMessage(); + } else if (e.key === 'Tab') { + // Enhanced tab navigation for Chromebooks + e.preventDefault(); + const focusableElements = document.querySelectorAll( + 'button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])' + ) as NodeListOf; + + const currentIndex = Array.from(focusableElements).indexOf(document.activeElement as HTMLElement); + const nextIndex = e.shiftKey + ? (currentIndex > 0 ? currentIndex - 1 : focusableElements.length - 1) + : (currentIndex < focusableElements.length - 1 ? currentIndex + 1 : 0); + + focusableElements[nextIndex]?.focus(); } }; @@ -601,11 +631,19 @@ export default function ChatDetail({ chatId }: { chatId: string }) {
{chat.messages.length === 0 ? (
@@ -624,7 +662,8 @@ export default function ChatDetail({ chatId }: { chatId: string }) { >
diff --git a/components/dashboard/content.tsx b/components/dashboard/content.tsx index b06ab8d..7c8ba0e 100644 --- a/components/dashboard/content.tsx +++ b/components/dashboard/content.tsx @@ -80,7 +80,7 @@ export default function Content({ username, orderStats }: ContentProps) {
{/* Order Statistics */} -
+
{statsConfig.map((stat) => ( +
{[...Array(itemsCount)].map((_, i) => ( diff --git a/components/layout/sidebar.tsx b/components/layout/sidebar.tsx index 9b7222e..74df865 100644 --- a/components/layout/sidebar.tsx +++ b/components/layout/sidebar.tsx @@ -60,7 +60,7 @@ const Sidebar: React.FC = () => {