duoyun-ui
Version:
A lightweight desktop UI component library, implemented using Gem
343 lines (338 loc) • 13.7 kB
JavaScript
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
import { mediaQuery } from '@mantou/gem/helper/mediaquery';
import { adoptedStyle, attribute, connectStore, customElement, effect, mounted, property, state, } from '@mantou/gem/lib/decorators';
import { createState, css, GemElement, html } from '@mantou/gem/lib/element';
import { history } from '@mantou/gem/lib/history';
import { addListener, classMap } from '@mantou/gem/lib/utils';
import { icons } from '../lib/icons';
import { focusStyle } from '../lib/styles';
import { theme } from '../lib/theme';
import { isRemoteIcon } from '../lib/utils';
import '../elements/use';
const style = css `
:scope {
display: flex;
align-items: center;
gap: 2em;
background: ${theme.backgroundColor};
box-shadow: rgba(0, 0, 0, calc(${theme.maskAlpha} - 0.1)) 0px 0px 8px;
}
:scope,
.drawer-brand {
padding: 0.6em 1em;
}
.drawer-brand {
display: none;
}
li {
list-style: none;
}
dy-use:not(.menu) {
width: 1.2em;
}
.menu {
display: none;
}
:where(.brand, .navbar, .navbar-top-link, dy-link) {
display: flex;
align-items: center;
}
.brand {
gap: 0.5em;
}
.logo {
height: 2.6em;
}
.name {
font-size: 1.35em;
opacity: 0.65;
}
.navbar {
gap: 0.5em;
}
:where(.nav-list) {
display: contents;
}
.navbar-item-wrap {
position: relative;
}
.navbar-top-link {
cursor: pointer;
gap: 0.3em;
padding-inline: 0.5em;
line-height: 2.4;
border-radius: ${theme.normalRound};
opacity: 0.65;
}
.navbar-item-wrap:hover .navbar-top-link {
background: ${theme.lightBackgroundColor};
}
.dropdown {
display: none;
position: absolute;
flex-direction: column;
gap: 0.3em;
top: 100%;
left: 0;
min-width: max(100%, 10em);
width: max-content;
margin: 0;
padding: 0.5em;
line-height: 1.7;
background: ${theme.backgroundColor};
border-radius: ${theme.normalRound};
filter: drop-shadow(${theme.borderColor} 0px 0px 1px)
drop-shadow(rgba(0, 0, 0, calc(${theme.maskAlpha} - 0.1)) 0px 7px 10px);
}
:scope:where(:not(:state(switching))) :where(.navbar-item-wrap:where(:hover, :focus-within)) .dropdown {
display: flex;
}
.dropdown dy-link {
border-radius: ${theme.normalRound};
padding: 0.5em;
gap: 0.3em;
opacity: 0.65;
}
.dropdown dy-link:hover {
background: ${theme.lightBackgroundColor};
}
`;
const mobileStyle = css(mediaQuery.PHONE,
/*css*/ `
:scope {
gap: 1em;
}
.drawer-brand {
display: block;
position: sticky;
top: 0;
background: ${theme.backgroundColor};
z-index: 1;
border-block-end: 1px solid ${theme.borderColor};
margin-block-end: 1em;
}
.menu {
display: block;
width: 1.5em;
padding: 0.5em;
margin: -0.5em;
border-radius: 10em;
}
.navbar:not(.open) {
display: none;
}
.navbar {
position: fixed;
z-index: ${theme.popupZIndex};
inset: 0;
background: rgba(0, 0, 0, calc(${theme.maskAlpha}));
align-items: stretch;
}
.nav-list {
display: block;
width: 20em;
height: 100%;
margin: 0;
padding: 0;
background: ${theme.backgroundColor};
overflow: auto;
overscroll-behavior: none;
}
.nav-list > li {
padding-inline: 1em;
}
.nav-list > li:last-of-type {
margin-block-end: 3em;
}
.open-dropdown + .dropdown {
display: block;
padding-inline-start: 2em;
}
.dropdown {
position: relative;
display: none;
width: 100%;
box-sizing: border-box;
padding: 0;
min-width: auto;
filter: none;
}
.dropdown::before {
position: absolute;
content: '';
width: 1px;
height: 100%;
left: 1.2em;
top: 0;
background: ${theme.borderColor};
}
`);
let DyPatNavElement = (() => {
let _classDecorators = [customElement('dy-pat-nav'), adoptedStyle(style), adoptedStyle(mobileStyle), adoptedStyle(focusStyle), connectStore(history.store)];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
let _classSuper = GemElement;
let _name_decorators;
let _name_initializers = [];
let _name_extraInitializers = [];
let _links_decorators;
let _links_initializers = [];
let _links_extraInitializers = [];
let _logo_decorators;
let _logo_initializers = [];
let _logo_extraInitializers = [];
let _switching_decorators;
let _switching_initializers = [];
let _switching_extraInitializers = [];
let _private_blur_decorators;
let _private_blur_initializers = [];
let _private_blur_extraInitializers = [];
let _private_autoBlur_decorators;
let _private_autoBlur_initializers = [];
let _private_autoBlur_extraInitializers = [];
var DyPatNavElement = class extends _classSuper {
static { _classThis = this; }
static {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
_name_decorators = [attribute];
_links_decorators = [property];
_logo_decorators = [property];
_switching_decorators = [state];
_private_blur_decorators = [effect(() => [location.href])];
_private_autoBlur_decorators = [mounted()];
__esDecorate(null, null, _name_decorators, { kind: "field", name: "name", static: false, private: false, access: { has: obj => "name" in obj, get: obj => obj.name, set: (obj, value) => { obj.name = value; } }, metadata: _metadata }, _name_initializers, _name_extraInitializers);
__esDecorate(null, null, _links_decorators, { kind: "field", name: "links", static: false, private: false, access: { has: obj => "links" in obj, get: obj => obj.links, set: (obj, value) => { obj.links = value; } }, metadata: _metadata }, _links_initializers, _links_extraInitializers);
__esDecorate(null, null, _logo_decorators, { kind: "field", name: "logo", static: false, private: false, access: { has: obj => "logo" in obj, get: obj => obj.logo, set: (obj, value) => { obj.logo = value; } }, metadata: _metadata }, _logo_initializers, _logo_extraInitializers);
__esDecorate(null, null, _switching_decorators, { kind: "field", name: "switching", static: false, private: false, access: { has: obj => "switching" in obj, get: obj => obj.switching, set: (obj, value) => { obj.switching = value; } }, metadata: _metadata }, _switching_initializers, _switching_extraInitializers);
__esDecorate(null, null, _private_blur_decorators, { kind: "field", name: "#blur", static: false, private: true, access: { has: obj => #blur in obj, get: obj => obj.#blur, set: (obj, value) => { obj.#blur = value; } }, metadata: _metadata }, _private_blur_initializers, _private_blur_extraInitializers);
__esDecorate(null, null, _private_autoBlur_decorators, { kind: "field", name: "#autoBlur", static: false, private: true, access: { has: obj => #autoBlur in obj, get: obj => obj.#autoBlur, set: (obj, value) => { obj.#autoBlur = value; } }, metadata: _metadata }, _private_autoBlur_initializers, _private_autoBlur_extraInitializers);
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
DyPatNavElement = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
}
name = __runInitializers(this, _name_initializers, void 0);
links = (__runInitializers(this, _name_extraInitializers), __runInitializers(this, _links_initializers, void 0));
logo = (__runInitializers(this, _links_extraInitializers), __runInitializers(this, _logo_initializers, void 0));
switching = (__runInitializers(this, _logo_extraInitializers), __runInitializers(this, _switching_initializers, void 0));
navSlot = __runInitializers(this, _switching_extraInitializers);
#state = createState({
drawerOpen: false,
});
#onMobileItemClick = (evt) => {
evt.currentTarget.classList.toggle('open-dropdown');
};
#isOutwardLink(href) {
return new URL(href, location.origin).origin !== location.origin;
}
#renderBrand = () => {
return html `
<dy-link class="brand" title=${this.name} href="/">
${!this.logo
? ''
: isRemoteIcon(this.logo)
? html `<img class="logo" alt="Logo" src=${this.logo}></img>`
: html `<dy-use class="logo" aria-label="Logo" .element=${this.logo}></dy-use>`}
<span class="name">${this.name}</span>
</dy-link>
`;
};
#blur = __runInitializers(this, _private_blur_initializers, () => {
this.#state({ drawerOpen: false });
this.getRootNode().activeElement?.blur();
this.switching = true;
setTimeout(() => (this.switching = false), 60);
});
#autoBlur = (__runInitializers(this, _private_blur_extraInitializers), __runInitializers(this, _private_autoBlur_initializers, () => {
return addListener(document, 'visibilitychange', () => {
if (document.visibilityState === 'hidden') {
this.#blur();
}
});
}));
render = (__runInitializers(this, _private_autoBlur_extraInitializers), () => {
return html `
<dy-use
class="menu"
tabindex="0"
.element=${icons.menu}
@click=${() => this.#state({ drawerOpen: true })}
></dy-use>
${this.#renderBrand()}
<nav class=${classMap({ navbar: true, open: this.#state.drawerOpen })}>
<ul class="nav-list">
<li class="drawer-brand">${this.#renderBrand()}</li>
${this.links?.map(({ label, items, href }) => html `
<li class="navbar-item-wrap">
<dy-active-link
v-if=${!!href}
@click=${this.#onMobileItemClick}
tabindex="0"
class="navbar-top-link"
href=${href}
>${label}</dy-active-link
>
<div v-else @click=${this.#onMobileItemClick} tabindex="0" class="navbar-top-link">
${label}<dy-use .element=${icons.expand}></dy-use>
</div>
<ul v-if=${!!items} class="dropdown">
${items?.map((item) => html `
<li>
<dy-link href=${item.href}>
${item.label}
<dy-use
v-if=${this.#isOutwardLink(item.href)}
class="outward"
.element=${icons.outward}
></dy-use>
</dy-link>
</li>
`)}
</ul>
</li>
`)}
</ul>
<div style="flex-grow: 1" @click=${() => this.#state({ drawerOpen: false })}></div>
</nav>
${this.navSlot}
`;
});
};
return DyPatNavElement = _classThis;
})();
export { DyPatNavElement };
//# sourceMappingURL=nav.js.map