rem-notepad / src /App.tsx
algorembrant's picture
Upload 31 files
4af09f9 verified
import { useEffect, useState } from 'react';
import { getSettings, SettingsType, DEFAULT_SETTINGS, getBackgroundImage } from './lib/db';
import { useFileStore } from './stores/fileStore';
import TreeView from './components/Sidebar/TreeView';
import EditorCore from './components/Editor/EditorCore';
import SettingsModal from './components/Settings/SettingsModal';
import {
Settings01Icon, Download01Icon, BorderAll01Icon
} from 'hugeicons-react';
function App() {
const [settings, setSettings] = useState<SettingsType>(DEFAULT_SETTINGS);
const [bgImage, setBgImage] = useState<string | null>(null);
const [showSettings, setShowSettings] = useState(false);
const [showSidebar, setShowSidebar] = useState(true);
const { loadFiles } = useFileStore();
useEffect(() => {
// Initial data load
loadFiles();
// Load config from DB
getSettings().then(setSettings);
// Load background image
getBackgroundImage().then(blob => {
if (blob) {
if (blob instanceof Blob) {
setBgImage(URL.createObjectURL(blob));
} else {
setBgImage(blob);
}
}
});
// Entry/Exit Listener
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
setShowSettings(false);
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
return (
<div
className={`app-container font-${settings.typography.replace(/\s+/g, '-').toLowerCase()}`}
style={{ '--bg-opacity': settings.bgOpacity, '--fg-opacity': settings.fgOpacity } as any}
>
{bgImage && (
<div
className="app-background"
style={{ backgroundImage: `url(${bgImage})` }}
/>
)}
{showSettings && <SettingsModal onClose={() => setShowSettings(false)} />}
<aside className="mini-sidebar">
<button
className={`btn-icon ${showSidebar ? 'active' : ''}`}
onClick={() => setShowSidebar(!showSidebar)}
title="Toggle Sidebar"
style={{ padding: 8, background: showSidebar ? 'rgba(0,0,0,0.03)' : 'transparent' }}
>
<BorderAll01Icon size={20} color={showSidebar ? 'var(--text-primary)' : 'var(--text-secondary)'} />
</button>
<div style={{ flex: 1 }} />
<button className="btn-icon" onClick={() => setShowSettings(true)} title="Settings" style={{ padding: 8 }}>
<Settings01Icon size={20} color="var(--text-secondary)" />
</button>
<button
className="btn-icon"
onClick={async () => {
const { exportFullWorkspace } = await import('./lib/db');
const data = await exportFullWorkspace();
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `hybrid-workspace-${new Date().toISOString().split('T')[0]}.json`;
a.click();
}}
title="Download Workspace"
style={{ padding: 8 }}
>
<Download01Icon size={20} color="var(--text-secondary)" />
</button>
</aside>
{showSidebar && (
<aside className="sidebar-panel">
<div className="sidebar-header" style={{ padding: '4px 16px', display: 'flex', alignItems: 'center', height: '48px', borderBottom: '1px solid var(--border-color)' }}>
<span style={{ letterSpacing: '0.05em', textTransform: 'uppercase', fontSize: '10px', fontWeight: 700, opacity: 0.4 }}>WORKSPACE</span>
</div>
<TreeView />
</aside>
)}
<main className="editor-main">
<EditorCore />
</main>
</div>
);
}
export default App;