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 = () => {