File size: 4,106 Bytes
d2c65ec
8052574
 
 
592d76b
8052574
728283f
165565d
8052574
 
 
d2c65ec
9d341c1
8052574
 
 
d2c65ec
 
 
8052574
 
 
 
 
 
 
 
 
 
 
728283f
8052574
 
9d341c1
 
 
8052574
 
 
d2c65ec
 
 
 
 
 
 
 
 
 
 
 
 
 
8052574
 
 
 
 
 
 
d2c65ec
 
 
 
 
 
 
 
 
 
8052574
 
 
 
60c1bf8
 
8052574
 
 
 
 
 
 
 
165565d
 
 
8052574
 
 
 
 
 
592d76b
 
 
728283f
 
 
 
8052574
 
 
165565d
 
 
 
 
8052574
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import React, { useEffect } from 'react';
import NavDrawer from './NavDrawer';
import ReaderPanel from './ReaderPanel';
import RightToolbar from '../toolbar/RightToolbar';
import MobileBottomBar from './MobileBottomBar';
import AIPopup from '../ai/AIPopup';
import AIFloatingMenu from '../ai/AIFloatingMenu';
import ErrorBoundary from '../common/ErrorBoundary';
import { Menu } from 'lucide-react';
import { useUIStore, useThemeStore } from '../../stores/appStore';
import { useAIStore } from '../../stores/aiStore';
import { AnimatePresence, motion } from 'framer-motion';
import { useKeyboardNav } from '../../hooks/useKeyboardNav';

// Shell = NavDrawer bg per theme β€” seamless sidebar integration
const SHELL_BG: Record<string, string> = {
  dark:    'theme-dark-bg',
  light:   'theme-light-bg',
  classic: 'theme-classic-bg',
};

// Menu button bg per theme (matches RightToolbar bg for visual consistency)
const MENU_BTN: Record<string, string> = {
  dark:    'bg-[#222242] hover:bg-[#2a2a4e]',
  light:   'bg-[#e8e0c8] hover:bg-[#ddd5bd]',
  classic: 'bg-[#e0d5b8] hover:bg-[#d5caad]',
};

const AppShell: React.FC = () => {
  const { toggleNav, isNavOpen } = useUIStore();
  const { isOpen } = useAIStore();
  const { theme } = useThemeStore();

  // Keyboard shortcut: ← β†’  PgUp PgDown Space for page navigation
  useKeyboardNav();

  const shellBg = SHELL_BG[theme] ?? SHELL_BG.dark;
  const menuBtn = MENU_BTN[theme] ?? MENU_BTN.dark;

  // ── Scroll Progress ────────────────────────────────────────
  const [scrollProgress, setScrollProgress] = React.useState(0);
  useEffect(() => {
    const el = document.getElementById('reader-scroll-container');
    if (!el) return;
    const handleScroll = () => {
      const total = el.scrollHeight - el.clientHeight;
      if (total <= 0) { setScrollProgress(0); return; }
      setScrollProgress((el.scrollTop / total) * 100);
    };
    el.addEventListener('scroll', handleScroll);
    return () => el.removeEventListener('scroll', handleScroll);
  }, []);

  return (
    <div className={`flex h-screen overflow-hidden ${shellBg}`}>
      {/* Left: NavDrawer */}
      <NavDrawer />

      {/* Centre: Reader β€” right-padded to clear RightToolbar (44px) on desktop */}
      <div className="flex-1 flex flex-col relative overflow-hidden lg:pr-11">
        {/* Scroll Progress Bar */}
        <div className="absolute top-0 left-0 right-0 h-0.5 z-40 bg-white/5">
          <motion.div
            className="h-full bg-[#c8860a]"
            initial={{ width: 0 }}
            animate={{ width: `${scrollProgress}%` }}
            transition={{ type: 'spring', stiffness: 300, damping: 30 }}
          />
        </div>

        {/* Menu button β€” visible only when drawer is closed */}
        {!isNavOpen && (
          <button
            onClick={toggleNav}
            style={{ top: 'calc(env(safe-area-inset-top) + 12px)' }}
            className={`fixed left-4 z-30 w-10 h-10 flex items-center justify-center rounded-full ${menuBtn} text-[#c8860a] transition-colors`}
            title="ΰΉ€ΰΈ›ΰΈ΄ΰΈ”ΰΉ€ΰΈ‘ΰΈ™ΰΈΉ"
          >
            <Menu size={20} />
          </button>
        )}

        {/* Scrollable reader β€” id is referenced by RightToolbar scroll-to-top */}
        <div id="reader-scroll-container" className="flex-1 overflow-y-auto scroll-smooth">
          <ErrorBoundary componentName="ReaderPanel">
            <ReaderPanel />
          </ErrorBoundary>
        </div>
      </div>

      {/* Right: Reading controls toolbar */}
      <RightToolbar />

      {/* Mobile: bottom navigation bar (hidden on desktop) */}
      <MobileBottomBar />

      {/* AI Floating Menu */}
      <ErrorBoundary componentName="AIFloatingMenu">
        <AIFloatingMenu />
      </ErrorBoundary>

      {/* AI Popup */}
      <AnimatePresence>
        {isOpen && (
          <ErrorBoundary componentName="AIPopup">
            <AIPopup />
          </ErrorBoundary>
        )}
      </AnimatePresence>
    </div>
  );
};

export default AppShell;