// Shell: topbar + left rail + viewport + AI panel + command palette
const MODULES = [
{ id: 'home', label: 'Home', letter: '', color: 'var(--ks-primary)', icon: 'home' },
{ id: 'word', label: 'Word', letter: 'W', color: 'var(--mod-word)', accent: 'word' },
{ id: 'sheets', label: 'Sheets', letter: 'S', color: 'var(--mod-sheets)', accent: 'sheets' },
{ id: 'slides', label: 'Slides', letter: 'P', color: 'var(--mod-slides)', accent: 'slides' },
{ id: 'pdf', label: 'PDF', letter: 'F', color: 'var(--mod-pdf)', accent: 'pdf' },
{ id: 'notes', label: 'Notes', letter: 'N', color: 'var(--mod-notes)', accent: 'notes' },
{ id: 'board', label: 'Board', letter: 'B', color: 'var(--mod-board)', accent: 'board' },
{ id: 'db', label: 'Database', letter: 'D', color: 'var(--mod-db)', accent: 'db' },
{ id: 'admin', label: 'Admin', letter: '', color: 'var(--mod-admin)', icon: 'shieldCheck' },
];
function Topbar({ onSearch, onToggleAI, aiOpen, moduleTitle, moduleAccent }) {
return (
);
}
function Rail({ current, onNavigate }) {
return (
);
}
// AI panel — contextual to current module
function AIPanel({ open, module, onClose }) {
const [msgs, setMsgs] = React.useState([
{ role: 'ai', text: 'I can help draft, summarise, translate, or analyse in this workspace. What would you like to do?' },
]);
const [input, setInput] = React.useState('');
const suggestions = {
home: ['Summarise my day', 'Draft a status update to my Director', 'Find last week\'s Cabinet Note', 'Translate the DPI Roadmap to Hindi'],
word: ['Proofread this document', 'Summarise in 5 bullets', 'Translate to हिंदी', 'Suggest a stronger opening paragraph'],
sheets: ['Explain this formula', 'Generate a formula to compute % utilisation', 'Recommend a chart for this data', 'Find outliers in column D'],
slides: ['Generate a slide from these notes', 'Suggest speaker notes for slide 3', 'Convert this section into 3 slides', 'Design a summary slide'],
pdf: ['Extract key clauses', 'Redact PII', 'Compare with previous version', 'Summarise this gazette'],
notes: ['Turn this note into action items', 'Transcribe last audio note', 'Convert to formal minutes', 'Tag related meetings'],
board: ['Convert this into a flowchart', 'Cluster these sticky notes', 'Draft a summary from the whiteboard', 'Suggest missing steps'],
db: ['Write a SQL query for high-priority open cases', 'Explain this table schema', 'Detect anomalies in SLA breaches'],
admin: ['Draft this month\'s compliance report', 'Find users with elevated access', 'Summarise recent audit events'],
}[module] || [];
const send = (text) => {
const t = (text ?? input).trim();
if (!t) return;
setMsgs(m => [...m, { role: 'user', text: t }]);
setInput('');
setTimeout(() => {
setMsgs(m => [...m, { role: 'ai', text: 'Working on it… I will draft a response, cite relevant documents from your workspace, and flag any DPDP-sensitive content before I return the result.' }]);
}, 420);
};
if (!open) return null;
return (
);
}
// Command palette
function CommandPalette({ open, onClose, onNavigate }) {
const [q, setQ] = React.useState('');
const inputRef = React.useRef(null);
React.useEffect(() => { if (open) setTimeout(() => inputRef.current?.focus(), 30); }, [open]);
React.useEffect(() => { if (!open) setQ(''); }, [open]);
const items = [
...MODULES.filter(m => m.id !== 'home').map(m => ({ kind:'nav', id:m.id, label:'Go to ' + m.label, hint:'Module', color:m.color })),
{ kind:'action', id:'new-doc', label:'New Word document', hint:'Create', color:'var(--mod-word)' },
{ kind:'action', id:'new-sheet', label:'New Spreadsheet', hint:'Create', color:'var(--mod-sheets)' },
{ kind:'action', id:'new-deck', label:'New Presentation', hint:'Create', color:'var(--mod-slides)' },
{ kind:'action', id:'new-note', label:'New Note', hint:'Create', color:'var(--mod-notes)' },
{ kind:'action', id:'ai-summ', label:'AI: Summarise this document', hint:'AI', color:'var(--mod-ai)' },
{ kind:'action', id:'ai-trans', label:'AI: Translate to हिंदी', hint:'AI', color:'var(--mod-ai)' },
...KS_DATA.recentDocs.slice(0,6).map(d => ({ kind:'doc', id:d.id, label:d.title, hint:'Recent · '+d.owner, color:'var(--mod-'+d.mod+')' })),
];
const filtered = q ? items.filter(i => i.label.toLowerCase().includes(q.toLowerCase())) : items;
if (!open) return null;
return (
e.stopPropagation()}>
{filtered.slice(0,12).map(item => (
))}
{filtered.length === 0 &&
No matches.
}
↑↓ navigate
↵ select
esc close
);
}
Object.assign(window, { Topbar, Rail, AIPanel, CommandPalette, MODULES });