mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 18:01:09 +02:00
Add new @manacore/shared-splitscreen package enabling iFrame-based
split-screen functionality across Calendar, Todo, and Contacts apps.
Features:
- SplitPaneContainer with CSS Grid layout
- AppPanel with iFrame sandbox permissions and loading/error states
- ResizeHandle with mouse, touch, and keyboard support (20-80% range)
- PanelControls for swap and close actions
- Svelte 5 runes-based store with Context API
- URL persistence (?panel=todo&split=60)
- localStorage persistence with versioning
- Mobile auto-disable (<1024px breakpoint)
Integration:
- PillNavigation: added onOpenInPanel prop and Ctrl/Cmd+click support
- PillDropdown: added split button per app item
- Calendar, Todo, Contacts layouts wrapped with SplitPaneContainer
Also fixes:
- WeekView.svelte: fixed {@const} placement error
- MultiDayView.svelte: fixed {@const} placement error
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
/**
|
|
* URL State Utilities
|
|
* Handle URL-based state persistence for split-screen.
|
|
*/
|
|
|
|
import type { UrlState } from '../types.js';
|
|
|
|
/**
|
|
* Parse split-screen state from URL search params.
|
|
* Reads `?panel=todo&split=60` format.
|
|
*/
|
|
export function parseUrlState(searchParams: URLSearchParams): UrlState {
|
|
const panel = searchParams.get('panel') || undefined;
|
|
const splitStr = searchParams.get('split');
|
|
const split = splitStr ? parseInt(splitStr, 10) : undefined;
|
|
|
|
return {
|
|
panel,
|
|
split: split && !isNaN(split) ? split : undefined,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Update URL with split-screen state without page reload.
|
|
* Uses replaceState to avoid adding to browser history.
|
|
*/
|
|
export function updateUrlState(state: UrlState): void {
|
|
if (typeof window === 'undefined') return;
|
|
|
|
const url = new URL(window.location.href);
|
|
|
|
if (state.panel) {
|
|
url.searchParams.set('panel', state.panel);
|
|
} else {
|
|
url.searchParams.delete('panel');
|
|
}
|
|
|
|
if (state.split && state.split !== 50) {
|
|
url.searchParams.set('split', state.split.toString());
|
|
} else {
|
|
url.searchParams.delete('split');
|
|
}
|
|
|
|
window.history.replaceState({}, '', url.toString());
|
|
}
|
|
|
|
/**
|
|
* Clear split-screen state from URL.
|
|
*/
|
|
export function clearUrlState(): void {
|
|
if (typeof window === 'undefined') return;
|
|
|
|
const url = new URL(window.location.href);
|
|
url.searchParams.delete('panel');
|
|
url.searchParams.delete('split');
|
|
window.history.replaceState({}, '', url.toString());
|
|
}
|
|
|
|
/**
|
|
* Get current URL state.
|
|
*/
|
|
export function getCurrentUrlState(): UrlState {
|
|
if (typeof window === 'undefined') return {};
|
|
return parseUrlState(new URLSearchParams(window.location.search));
|
|
}
|