@wuisdk/shell 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ ## @wuisdk/shell
2
+ - @wuisdk/shell/desktop
3
+ - @wuisdk/shell/mobile
4
+
5
+ ### App Shell
6
+ ```html
7
+ <div class="wui">
8
+ <aside class="wui-sidebar"></aside>
9
+ <div class="wui-shell">
10
+ <main class="wui-content"></main>
11
+ <div class="wui-loader"></div>
12
+ </div>
13
+ <nav class="wui-tabbar"></nav>
14
+ </div>
15
+ ```
16
+
17
+ ### Overlay Root
18
+ ```html
19
+ <div class="overlay-root">
20
+ <div class="overlay-backdrop"></div>
21
+ <div class="overlay-layer" data-type="drawer"></div>
22
+ <div class="overlay-layer" data-type="modal"></div>
23
+ <div class="overlay-layer" data-type="dialog"></div>
24
+ <div class="overlay-layer" data-type="popover"></div>
25
+ <div class="overlay-layer" data-type="toast"></div>
26
+ </div>
27
+ ```
@@ -0,0 +1,50 @@
1
+ import { a as ViewportSize, i as ThemeMode, r as SidebarState } from "./types-ayz5MABs.js";
2
+ import { BaseComponent, IAppShell, ShellType, StoreListener, StoreSelector, SubscribeOptions } from "@wuisdk/core";
3
+ //#region src/store.d.ts
4
+ declare module '@wuisdk/core' {
5
+ interface WuiStoreMap {
6
+ layout: ShellLayoutStore;
7
+ }
8
+ }
9
+ interface LayoutState {
10
+ theme: ThemeMode;
11
+ shell: ShellType;
12
+ viewport: ViewportSize;
13
+ sidebar: SidebarState;
14
+ sidebarPref?: SidebarState;
15
+ }
16
+ declare class ShellLayoutStore {
17
+ private store;
18
+ get state(): Readonly<LayoutState>;
19
+ subscribe<R>(selector: StoreSelector<LayoutState, R>, handler: StoreListener<R>, options?: SubscribeOptions<R>): () => void;
20
+ updateLayout(updates: Partial<LayoutState>): void;
21
+ toggleSidebar(): void;
22
+ private calcSidebarState;
23
+ }
24
+ //#endregion
25
+ //#region src/regions/wui-shell.d.ts
26
+ declare class WuiShell extends BaseComponent {
27
+ private content;
28
+ private loader;
29
+ constructor();
30
+ protected render(): void;
31
+ protected onDestroy(): void;
32
+ get wuiContent(): HTMLElement;
33
+ }
34
+ //#endregion
35
+ //#region src/shell/base.shell.d.ts
36
+ declare abstract class BaseShell extends BaseComponent implements IAppShell {
37
+ protected wuiShell: WuiShell;
38
+ constructor();
39
+ protected onMount(): void;
40
+ protected onDestroy(): void;
41
+ get wuiRoot(): HTMLElement;
42
+ get wuiContent(): HTMLElement;
43
+ protected abstract readonly layoutStore: ShellLayoutStore;
44
+ protected abstract onShellMount(): void;
45
+ protected abstract onShellDestroy(): void;
46
+ private setupLayoutStateListener;
47
+ private setupSystemStateListener;
48
+ }
49
+ //#endregion
50
+ export { ShellLayoutStore as n, BaseShell as t };
@@ -0,0 +1 @@
1
+ @layer shell{.wui ::-webkit-scrollbar{width:var(--spacing-sm);height:var(--spacing-sm)}.wui ::-webkit-scrollbar-track{background:0 0}.wui ::-webkit-scrollbar-thumb{border-radius:var(--radius-full);background:#0000001a}}
@@ -0,0 +1,16 @@
1
+ import { n as RegionsConfig } from "../types-ayz5MABs.js";
2
+ import { n as ShellLayoutStore, t as BaseShell } from "../base.shell-BD3tzDD9.js";
3
+ //#region src/shell/desktop.d.ts
4
+ declare class DesktopShell extends BaseShell {
5
+ private sidebar;
6
+ private viewport;
7
+ private indicator;
8
+ protected readonly layoutStore: ShellLayoutStore;
9
+ constructor(config?: RegionsConfig);
10
+ protected render(): void;
11
+ protected onShellMount(): void;
12
+ protected onShellDestroy(): void;
13
+ private setupPrefState;
14
+ }
15
+ //#endregion
16
+ export { DesktopShell };
@@ -0,0 +1,2 @@
1
+ import './index.css';
2
+ import{i as e,n as t,o as n,r,t as i}from"../viewport-BEoQW1zd.js";var a=class extends e{sidebar;viewport;indicator=new i;layoutStore=new r;constructor(e={}){super(),this.sidebar=new n(e.sidebar),this.viewport=new t(this.layoutStore)}render(){}onShellMount(){this.sidebar.injectContext(this.ctx).mount(this.element),this.wuiShell.injectContext(this.ctx).mount(this.element),this.indicator.injectContext(this.ctx).mount(this.element),this.setupPrefState(),this.viewport.observe()}onShellDestroy(){this.sidebar.destroy(),this.viewport.disconnect()}setupPrefState(){let{storage:e}=this.ctx.config,t=localStorage.getItem(e.SIDEBAR_STATE);t&&[`expanded`,`collapsed`].includes(t)&&this.layoutStore.updateLayout({sidebarPref:t}),this.layoutStore.subscribe(e=>e.sidebarPref,t=>{t&&[`expanded`,`collapsed`].includes(t)&&localStorage.setItem(e.SIDEBAR_STATE,t)},{signal:this.signal})}};export{a as DesktopShell};
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ @layer layout{.wui{grid-template-columns:1fr;width:100%;height:100dvh;display:grid;overflow:hidden}.wui-shell{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;position:relative;overflow:hidden}.wui-content{flex:1;min-width:0;min-height:0;overflow:auto}.wui-viewport{left:var(--spacing-sm);color:var(--color-text-muted);z-index:var(--z-overlay-root);font-size:10px;line-height:1;position:fixed}.wui[data-shell=dashboard]:not([data-sidebar=overlay],[data-sidebar=hidden]){grid-template-columns:auto 1fr}.wui[data-shell=dashboard]:not([data-sidebar=overlay],[data-sidebar=hidden]) .wui-content{margin:var(--spacing-md);border:1px solid var(--color-border-soft);border-radius:var(--radius-xl);background-color:var(--color-surface);margin-left:0;overflow:hidden}.wui[data-shell=dashboard]:is([data-sidebar=overlay],[data-sidebar=hidden]) .wui-content{background-color:var(--color-surface);overflow:hidden}.wui[data-shell=auth] .wui-content{background:linear-gradient(135deg,#f8fafd 0%,#eef2f8 45%,#e2e8f3 100%)}.wui[data-shell=auth] .wui-page,.wui[data-shell=auth] .wui-loader{justify-content:center;align-items:center}.wui-loader{padding:5.5rem var(--spacing-lg);transition:var(--fade-transition);z-index:var(--z-above);opacity:0;visibility:hidden;justify-content:center;display:flex;position:absolute;inset:0}.wui[data-loading=true] .wui-loader{opacity:1;visibility:visible}.wui-spinner{width:48px;height:48px;display:block;position:relative}.wui-spinner div{transform-origin:24px 24px;animation:1.2s linear infinite fade-out}.wui-spinner div:after{content:"";background-color:var(--color-primary);border-radius:2px;width:4px;height:11px;display:block;position:absolute;top:3px;left:22px}.wui-spinner div:first-child{animation-delay:-1.1s;transform:rotate(0)}.wui-spinner div:nth-child(2){animation-delay:-1s;transform:rotate(30deg)}.wui-spinner div:nth-child(3){animation-delay:-.9s;transform:rotate(60deg)}.wui-spinner div:nth-child(4){animation-delay:-.8s;transform:rotate(90deg)}.wui-spinner div:nth-child(5){animation-delay:-.7s;transform:rotate(120deg)}.wui-spinner div:nth-child(6){animation-delay:-.6s;transform:rotate(150deg)}.wui-spinner div:nth-child(7){animation-delay:-.5s;transform:rotate(180deg)}.wui-spinner div:nth-child(8){animation-delay:-.4s;transform:rotate(210deg)}.wui-spinner div:nth-child(9){animation-delay:-.3s;transform:rotate(240deg)}.wui-spinner div:nth-child(10){animation-delay:-.2s;transform:rotate(270deg)}.wui-spinner div:nth-child(11){animation-delay:-.1s;transform:rotate(300deg)}.wui-spinner div:nth-child(12){animation-delay:0s;transform:rotate(330deg)}:root{--sidebar-expanded-width:224px;--sidebar-collapsed-width:64px;--sidebar-bg:var(--color-bg)}.wui-sidebar{width:0;padding:var(--spacing-sm);background-color:var(--sidebar-bg);z-index:var(--z-sidebar);transition:width var(--transition-base), transform var(--transition-base);flex-direction:column;display:flex;position:fixed;inset:0 auto 0 0;overflow:hidden;transform:translate(-100%)}.sidebar__header{height:3rem;padding:0 var(--spacing-md);flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.sidebar__logo{padding-left:var(--spacing-lg);font-family:var(--font-heading);font-size:var(--font-size-heading);color:var(--color-primary-text);white-space:nowrap;font-weight:600;overflow:hidden}.sidebar__toggle{border-radius:var(--radius-full);width:32px;height:32px;font-size:var(--font-xl);color:var(--color-primary-text);background-color:#0000;flex-shrink:0;padding:0}.sidebar__footer{height:3.5rem;padding:var(--spacing-sm);flex-shrink:0}.profile{justify-content:flex-start;gap:var(--spacing-md);width:100%;height:100%;padding:0 var(--spacing-md);background-color:#0000}.profile__avatar{width:2.25rem;height:2.25rem;padding:var(--spacing-xs);border-radius:var(--radius-full);background:#0000001a;flex-shrink:0;overflow:hidden}.profile__avatar img{border-radius:var(--radius-full);width:100%;height:100%;display:block}.profile__info{min-width:0;font-family:var(--font-body);text-align:left;white-space:nowrap;overflow:hidden}.profile__info :first-child{line-height:1.5;font-size:var(--font-sm);font-weight:500}.profile__info :last-child{line-height:1.25;font-size:var(--font-xs);color:var(--color-text-muted)}.wui[data-shell=dashboard][data-sidebar=collapsed] .wui-sidebar{width:var(--sidebar-collapsed-width);position:relative;transform:translate(0)}.wui[data-shell=dashboard][data-sidebar=expanded] .wui-sidebar{width:var(--sidebar-expanded-width);position:relative;transform:translate(0)}.wui[data-shell=dashboard][data-sidebar=overlay] .wui-sidebar{width:var(--sidebar-expanded-width);box-shadow:var(--shadow-lg);transform:translate(0)}.wui[data-sidebar=collapsed] .sidebar__logo,.wui[data-sidebar=collapsed] .profile__info{display:none}.wui[data-sidebar=collapsed] .sidebar__header,.wui[data-sidebar=collapsed] .profile{justify-content:center;padding:0}@media (hover:hover) and (pointer:fine){.sidebar__toggle:hover{background-color:var(--nav-item-bg-hover)}.profile:hover{color:var(--nav-item-text-hover);background-color:var(--nav-item-bg-hover)}}:root{--nav-item-text:var(--color-slate-500);--nav-item-text-hover:var(--color-slate-600);--nav-item-text-active:var(--color-primary-text);--nav-item-bg-hover:#0000000a;--nav-item-bg-active:var(--color-primary-100);--nav-item-border-active:rgb(from var(--color-primary-200) r g b / 25%)}.sidebar__nav{padding:var(--spacing-md);white-space:nowrap;scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;flex:1;overflow:hidden auto}.nav-item,.nav-subitem{justify-content:flex-start;align-items:center;gap:var(--spacing-md);padding:0 var(--spacing-lg);border-radius:var(--radius-md);margin-bottom:var(--spacing-sm);user-select:none;color:var(--nav-item-text);font-size:var(--font-size-label);background-color:#0000;border:1px solid #0000;width:100%;min-width:0;height:2.5rem;font-weight:500;text-decoration:none;display:flex}.nav-item[data-active],.nav-subitem[data-active]{color:var(--nav-item-text-active);background:var(--nav-item-bg-active);border-color:var(--nav-item-border-active)}.nav-item[data-active] .nav-icon,.nav-subitem[data-active] .nav-icon{font-weight:900}.nav-icon,.nav-caret{text-align:left;min-width:22px;line-height:1;font-family:var(--font-icon);font-size:var(--font-md);flex-shrink:0}.nav-label{text-align:left;font-family:var(--font-heading);white-space:nowrap;flex:1}.nav-group{flex-direction:column;display:flex}.nav-group[data-open=true]{margin-bottom:var(--spacing-sm)}.nav-caret{min-width:auto;transition:transform var(--transition-fast)}.nav-group[data-open=true] .nav-caret{transform:rotate(90deg)}.nav-children{visibility:hidden;opacity:0;grid-template-rows:0fr;transition:opacity .2s ease-out,grid-template-rows .2s ease-out;display:grid}.nav-group[data-open=true] .nav-children{visibility:visible;opacity:1;grid-template-rows:1fr}.nav-children>*{min-height:0}.nav-children__wrapper{border-left:2px solid #0000000a;padding:0 3px;overflow:hidden}.nav-subitem{height:32px;font-size:var(--font-sm);padding:0 6px}.nav-subitem:last-child{margin-bottom:0}.nav-subitem .nav-icon{text-align:right}.wui[data-sidebar=collapsed] .nav-item,.wui[data-sidebar=collapsed] .nav-subitem{justify-content:center}.wui[data-sidebar=collapsed] .nav-label,.wui[data-sidebar=collapsed] .nav-caret{display:none}.wui[data-sidebar=collapsed] .nav-icon{min-width:auto;font-size:var(--font-lg)}@media (hover:hover) and (pointer:fine){.nav-item:hover:not([data-active]),.nav-subitem:hover:not([data-active]){color:var(--nav-item-text-hover);background-color:var(--nav-item-bg-hover)}}:root{--tabbar-height:56px}.wui-tabbar{padding:var(--spacing-lg);padding-bottom:calc(var(--spacing-md) + env(safe-area-inset-bottom));z-index:var(--z-tabbar);pointer-events:none;justify-content:center;align-items:center;display:flex;position:fixed;bottom:0;left:0;right:0}.tabbar__list{width:100%;max-width:400px;height:var(--tabbar-height);padding:0 var(--spacing-md);border-radius:var(--radius-full);-webkit-backdrop-filter:blur(16px);pointer-events:auto;background-color:#ffffffd1;border:1px solid #fff9;justify-content:space-between;align-items:center;display:flex;box-shadow:0 1px 2px #0000000d,0 8px 16px #0000000f,0 16px 32px #1018280a,0 0 0 1px #00000005}.tabbar__item{justify-content:center;align-items:center;gap:var(--spacing-sm);color:inherit;flex-direction:column;flex:1;height:100%;text-decoration:none;display:flex}.tabbar__icon{line-height:1;font-family:var(--font-icon);font-size:var(--font-xl);transition:font-weight .2s,transform .3s cubic-bezier(.34,1.56,.64,1)}.tabbar__label{line-height:1;font-family:var(--font-heading);font-size:11px}.tabbar__item[data-active]{color:var(--color-primary)}.tabbar__item[data-active] .tabbar__icon{font-weight:900;transform:translateY(-2px)scale(1.1)}@media (hover:hover) and (pointer:fine){.tabbar__item:not([data-active]):hover{color:var(--color-slate-600)}}.wui-page{min-width:0;height:100%;min-height:0;transition:var(--fade-transition);opacity:0;visibility:hidden;flex-direction:column;display:flex;overflow:hidden}.wui[data-ready=true] .wui-page{opacity:1;visibility:visible}.page-header,.page-footer{justify-content:space-between;align-items:center;gap:var(--spacing-md);padding:0 var(--spacing-xl);z-index:var(--z-above);height:3rem;transition:box-shadow var(--transition-fast), background-color var(--transition-fast);display:flex}.page-body{min-width:0;min-height:0;padding:var(--spacing-xl);flex:1;overflow:auto}.page-header.has-shadow{background-color:var(--color-surface);box-shadow:0 4px 12px #0000000f,0 1px 2px #0000000a}.page-header__main,.page-header__actions{align-items:center;gap:var(--spacing-md);display:flex}.page-header__main{flex:1;min-width:0}.page-header__actions{flex-shrink:0}.page-title{padding:0 var(--spacing-sm);font-family:var(--font-heading);font-size:var(--font-size-title);white-space:nowrap;text-overflow:ellipsis;margin:0;font-weight:600;overflow:hidden}.page-header__actions .btn--circle{font-size:var(--font-lg)!important}.page-scroll-sentinel{visibility:hidden;pointer-events:none;height:1px;margin-top:-1px}}
@@ -0,0 +1,8 @@
1
+ import { t as NavItem } from "./types-ayz5MABs.js";
2
+ //#region src/index.d.ts
3
+ declare const info: () => {
4
+ version: string;
5
+ name: string;
6
+ };
7
+ //#endregion
8
+ export { type NavItem, info };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import './index.css';
2
+ const e=()=>({version:`0.1.0`,name:`@wuisdk/shell`.split(`/`)[1]});export{e as info};
@@ -0,0 +1 @@
1
+ @layer shell{.wui{grid-template-columns:1fr}.wui .wui-content{background-color:#0000;border-color:#0000;border-radius:0;margin:0}}
@@ -0,0 +1,14 @@
1
+ import { n as RegionsConfig } from "../types-ayz5MABs.js";
2
+ import { n as ShellLayoutStore, t as BaseShell } from "../base.shell-BD3tzDD9.js";
3
+ //#region src/shell/mobile.d.ts
4
+ declare class MobileShell extends BaseShell {
5
+ private tabbar;
6
+ private viewport;
7
+ protected readonly layoutStore: ShellLayoutStore;
8
+ constructor(config?: RegionsConfig);
9
+ protected render(): void;
10
+ protected onShellMount(): void;
11
+ protected onShellDestroy(): void;
12
+ }
13
+ //#endregion
14
+ export { MobileShell };
@@ -0,0 +1,2 @@
1
+ import './index.css';
2
+ import{a as e,i as t,n,r}from"../viewport-BEoQW1zd.js";var i=class extends t{tabbar;viewport;layoutStore=new r;constructor(t={}){super(),this.tabbar=new e(t.tabbar),this.viewport=new n(this.layoutStore)}render(){}onShellMount(){this.wuiShell.injectContext(this.ctx).mount(this.element),this.tabbar.injectContext(this.ctx).mount(this.element),this.viewport.observe()}onShellDestroy(){this.tabbar.destroy(),this.viewport.disconnect()}};export{i as MobileShell};
@@ -0,0 +1,41 @@
1
+ //#region src/types.d.ts
2
+ type ThemeMode = 'light' | 'dark' | 'system';
3
+ type ViewportSize = 'sm' | 'md' | 'lg';
4
+ type SidebarState = 'expanded' | 'collapsed' | 'overlay' | 'hidden';
5
+ interface RegionBaseConfig {
6
+ readonly enabled?: boolean;
7
+ }
8
+ interface SidebarConfig extends RegionBaseConfig {
9
+ readonly menu?: NavItem[];
10
+ }
11
+ interface TabbarConfig extends RegionBaseConfig {
12
+ readonly menu?: NavItem[];
13
+ }
14
+ interface RegionsConfig {
15
+ readonly sidebar?: SidebarConfig;
16
+ readonly tabbar?: TabbarConfig;
17
+ }
18
+ interface BaseNavItem {
19
+ label: string;
20
+ icon?: string;
21
+ hidden?: boolean;
22
+ disabled?: boolean;
23
+ badge?: string | number;
24
+ }
25
+ interface NavLink extends BaseNavItem {
26
+ type: 'item';
27
+ path: string;
28
+ exact?: boolean;
29
+ }
30
+ interface NavGroup extends BaseNavItem {
31
+ type: 'group';
32
+ children: NavItem[];
33
+ defaultOpen?: boolean;
34
+ }
35
+ type Role = 'admin' | 'user' | 'guest';
36
+ interface WithPermission {
37
+ roles?: Role[];
38
+ }
39
+ type NavItem = (NavLink & WithPermission) | (NavGroup & WithPermission);
40
+ //#endregion
41
+ export { ViewportSize as a, ThemeMode as i, RegionsConfig as n, SidebarState as r, NavItem as t };
@@ -0,0 +1,17 @@
1
+ import{BaseComponent as e,Store as t}from"@wuisdk/core";import{dom as n}from"@wuisdk/utils";import{WuiActionMenu as r}from"@wuisdk/comps/dropdown";var i=class extends e{content=n.createElement(`main`,{className:`wui-content`});loader=n.createElement(`div`,{className:`wui-loader`});constructor(){super(`div`,{className:`wui-shell`})}render(){let e=n.createElement(`div`,{className:`wui-spinner`}),t=Array.from({length:12},()=>n.createElement(`div`));e.append(...t),this.loader.replaceChildren(e),this.element.append(this.content,this.loader)}onDestroy(){this.content.remove(),this.loader.remove()}get wuiContent(){return this.content}};const a=(e,t)=>{if(!e||!t)return;let n=`admin`,r=document.createDocumentFragment();t.forEach(e=>{e.roles&&!e.roles.includes(n)||e.hidden||(e.type===`item`&&r.append(o(e)),e.type===`group`&&r.append(s(e,n)))}),e.replaceChildren(r)},o=(e,t=!1)=>{let r=n.createElement(`a`,{className:t?`nav-subitem`:`nav-item`,attributes:{href:e.path??`#`},dataset:{wuiLink:``}}),i=n.createElement(`span`,{className:`nav-icon`},e.icon??``),a=n.createElement(`span`,{className:`nav-label`},e.label??``);return r.append(i,a),e.disabled&&r.classList.add(`is-disabled`),r},s=(e,t)=>{let r=n.createElement(`div`,{className:`nav-group`,dataset:{open:String(e.defaultOpen||!1)}}),i=n.createElement(`button`,{className:[`nav-item`,`has-children`]}),a=n.createElement(`span`,{className:`nav-icon`},e.icon??``),c=n.createElement(`span`,{className:`nav-label`},e.label??``),l=n.createElement(`span`,{className:`nav-caret`},``);i.append(a,c,l);let u=n.createElement(`div`,{className:`nav-children`}),d=n.createElement(`div`,{className:`nav-children__wrapper`});return e.children.forEach(e=>{e.roles&&!e.roles.includes(t)||(e.type===`item`?d.append(o(e,!0)):d.append(s(e,t)))}),u.appendChild(d),r.append(i,u),r};var c=`<div class="sidebar__header">
2
+ <div class="sidebar__logo">
3
+ <i class="fa-regular fa-fire"></i>
4
+ <span class="app-name">App Name</span>
5
+ </div>
6
+ <button class="sidebar__toggle">&#x2630;</button>
7
+ </div>
8
+ <nav class="sidebar__nav"></nav>
9
+ <div class="sidebar__footer">
10
+ <button class="profile">
11
+ <div class="profile__avatar"></div>
12
+ <div class="profile__info">
13
+ <div class="name">Display Name</div>
14
+ <div class="unit">Department Name</div>
15
+ </div>
16
+ </button>
17
+ </div>`,l=class extends e{config;navLink=[];profileAction=null;constructor(e={}){super(`aside`,{className:`wui-sidebar`}),this.config=e}render(){let e=n.renderTemplate(c);this.element.replaceChildren(e)}onMount(){this.setupNavMenu(),this.setProfileAction(),this.element.addEventListener(`click`,this.handleClick,{signal:this.signal}),this.ctx.events.on(`sys:route-changed`,e=>{this.setNavActive(e.path)},this.signal);let e=this.element.querySelector(`.app-name`);e&&(e.textContent=this.ctx.config.appName),this.ctx.stores.auth?.subscribe(e=>e.user,e=>this.setProfile(e),{signal:this.signal}),this.ctx.stores.fiber.subscribe(e=>e.user,e=>this.setAccess(e),{signal:this.signal})}onUnmount(){this.profileAction?.destroy(),this.profileAction=null}setNavActive(e){this.navLink.forEach(t=>{let n=t.getAttribute(`href`),r=n===e||n===`/${e}`;t.toggleAttribute(`data-active`,r)})}setupNavMenu(){let e=this.element.querySelector(`nav`);e&&this.config.menu&&(a(e,this.config.menu),this.navLink=Array.from(e.querySelectorAll(`[data-wui-link]`)))}handleClick=e=>{let t=e.target;if(t.closest(`.sidebar__toggle`)){this.ctx.stores.layout.toggleSidebar();return}let n=t.closest(`.nav-item.has-children`);if(n){e.preventDefault();let t=n.closest(`.nav-group`);if(t){let e=t.dataset.open===`true`;t.dataset.open=String(!e)}}};setProfile(e){if(!e)return;let t=this.element.querySelector(`.profile__avatar`);if(t&&e.picture){let r=n.createElement(`img`,{attributes:{src:e.picture}});t.replaceChildren(r)}let r=this.element.querySelector(`.profile__info .name`),i=this.element.querySelector(`.profile__info .unit`);r&&(r.textContent=e.name),i&&(i.textContent=e.unit)}setAccess(e){if(!e)return;let t=this.element.querySelector(`.profile__avatar`);if(t){let e=n.createElement(`img`,{attributes:{src:`https://cdn.jsdelivr.net/gh/wkrdev/assets/img/icon/icon-03.png`}});t.replaceChildren(e)}let r=this.element.querySelector(`.profile__info .name`),i=this.element.querySelector(`.profile__info .unit`);r&&(r.textContent=e.full_name),i&&(i.textContent=e.sect?e.sect_name:e.dvsn_name)}setProfileAction(){let e=[{id:`profile`,label:`โปรไฟล์`,icon:``},{id:`setting`,label:`การตั้งค่า`,icon:``},{id:`manual`,label:`ช่วยเหลือ`,icon:``},{id:`hwlink`,label:`HwLink`,icon:``},{divider:!0},{id:`logout`,label:`ลงชื่อออก`,icon:``,onClick:this.handleLogout}],t=this.element.querySelector(`.profile`);t&&(this.profileAction=new r({trigger:t,items:e,placement:`top-start`,signal:this.signal}).injectContext(this.ctx))}handleLogout=async()=>{await this.ctx.ui.dialog.confirm(`ยืนยัน.! การออกจากระบบ`)&&(this.ctx.plugins.auth&&this.ctx.plugins.auth.logout(),this.ctx.plugins.fiber&&this.ctx.plugins.fiber.logout())}},u=`<div class="tabbar__list"></div>`,d=class extends e{config;navLink=[];constructor(e={}){super(`nav`,{className:`wui-tabbar`}),this.config=e}render(){let e=n.renderTemplate(u);this.element.replaceChildren(e)}onMount(){this.setupTabMenu(),this.ctx.events.on(`sys:route-changed`,e=>{this.setNavActive(e.path)},this.signal)}setNavActive(e){this.navLink.forEach(t=>{let n=t.getAttribute(`href`),r=n===e||n===`/${e}`;t.toggleAttribute(`data-active`,r)})}setupTabMenu(){let e=this.element.querySelector(`.tabbar__list`);if(e&&this.config.menu){let t=document.createDocumentFragment();this.config.menu.forEach(e=>{if(e.type!==`item`)return;let r=n.createElement(`a`,{className:`tabbar__item`,attributes:{href:e.path,"data-wui-link":``}},n.createElement(`span`,{className:`tabbar__icon`},e.icon),n.createElement(`span`,{className:`tabbar__label`},e.label));t.appendChild(r)}),e.replaceChildren(t),this.navLink=Array.from(e.querySelectorAll(`[data-wui-link]`))}}},f=class extends e{wuiShell;constructor(){super(`div`,{className:`wui`}),this.wuiShell=new i}onMount(){this.ctx.registerStore(`layout`,this.layoutStore),this.setupLayoutStateListener(),this.setupSystemStateListener(),this.ctx.events.on(`sys:page-mounted`,e=>{this.layoutStore.updateLayout({shell:e.shell})}),this.onShellMount()}onDestroy(){this.wuiShell.destroy(),this.onShellDestroy()}get wuiRoot(){return this.element}get wuiContent(){return this.wuiShell.wuiContent}setupLayoutStateListener(){let e=this.layoutStore.state;Object.entries(e).forEach(([e,t])=>{e!==`sidebarPref`&&(this.element.dataset[e]=String(t))}),this.layoutStore.subscribe(e=>e,(e,t)=>{Object.entries(e).forEach(([e,n])=>{e!==`sidebarPref`&&(!t||t[e]!==n)&&(this.element.dataset[e]=String(n))})},{isEqual:(e,t)=>e===t?!0:!e||!t?!1:Object.keys(e).every(n=>e[n]===t[n]),signal:this.signal})}setupSystemStateListener(){let e=this.ctx.stores.sys,t=e.state;this.element.dataset.loading=String(t.loading),this.element.dataset.ready=String(t.ready),e.subscribe(e=>({loading:e.loading,ready:e.ready}),(e,t)=>{t.loading!==e.loading&&(this.element.dataset.loading=String(e.loading)),t.ready!==e.ready&&(this.element.dataset.ready=String(e.ready))},{isEqual:(e,t)=>e.loading===t.loading&&e.ready===t.ready,signal:this.signal})}},p=class{store=new t({theme:`system`,shell:`blank`,viewport:`sm`,sidebar:`hidden`});get state(){return this.store.getState()}subscribe(e,t,n){return this.store.subscribe(e,t,n)}updateLayout(e){this.store.setState(t=>{let n={...t,...e};return(e.shell!==void 0||e.viewport!==void 0)&&(n.sidebar=this.calcSidebarState(n.shell,n.viewport,n.sidebarPref)),n})}toggleSidebar(){this.store.setState(e=>{let{viewport:t,sidebar:n,shell:r,sidebarPref:i}=e;if(r!==`dashboard`)return{};let a,o=i;return t===`sm`?a=n===`hidden`?`overlay`:`hidden`:(a=n===`expanded`?`collapsed`:`expanded`,o=a),{sidebar:a,sidebarPref:o}})}calcSidebarState(e,t,n){return e!==`dashboard`||t===`sm`?`hidden`:n&&[`expanded`,`collapsed`].includes(n)?n:t===`md`?`collapsed`:`expanded`}},m=class{store;abortController=null;mediaQueries;constructor(e,t={md:`(min-width: 600px)`,lg:`(min-width: 800px)`}){this.store=e,this.mediaQueries={md:window.matchMedia(t.md),lg:window.matchMedia(t.lg)}}observe(){if(this.abortController)return;this.abortController=new AbortController;let{signal:e}=this.abortController,t=()=>{let e=`sm`;this.mediaQueries.lg.matches?e=`lg`:this.mediaQueries.md.matches&&(e=`md`),this.store.state.viewport!==e&&this.store.updateLayout({viewport:e})};Object.values(this.mediaQueries).forEach(n=>{n.addEventListener(`change`,t,{signal:e})}),t()}disconnect(){this.abortController&&=(this.abortController.abort(),null)}},h=class extends e{isTicking=!1;constructor(){super(`div`,{className:`wui-viewport`})}render(){this.updateDimensions()}onMount(){window.addEventListener(`resize`,this.handleResize,{signal:this.signal})}handleResize=()=>{this.isTicking||=(window.requestAnimationFrame(()=>{this.updateDimensions(),this.isTicking=!1}),!0)};updateDimensions(){let e=window.innerWidth,t=window.innerHeight;this.element.textContent=`${e}x${t}`}};export{d as a,f as i,m as n,l as o,p as r,h as t};
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@wuisdk/shell",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "import": "./dist/index.js",
8
+ "types": "./dist/index.d.ts"
9
+ },
10
+ "./*": {
11
+ "import": "./dist/*/index.js",
12
+ "types": "./dist/*/index.d.ts"
13
+ }
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsdown --minify",
23
+ "dev": "tsdown --no-clean --watch"
24
+ },
25
+ "dependencies": {
26
+ "@wuisdk/comps": "*",
27
+ "@wuisdk/core": "*",
28
+ "@wuisdk/utils": "*",
29
+ "@wuisdk/plugin-auth": "*",
30
+ "@wuisdk/plugin-fiber": "*"
31
+ },
32
+ "author": "hs3lcs@gmail.com",
33
+ "license": "MIT"
34
+ }