diff --git a/src/assets/default-avatar.png b/public/default-avatar.png similarity index 100% rename from src/assets/default-avatar.png rename to public/default-avatar.png diff --git a/src/assets/logo.png b/src/assets/logo.png deleted file mode 100644 index 2e3b818..0000000 Binary files a/src/assets/logo.png and /dev/null differ diff --git a/src/components/AppGrid.ts b/src/components/AppGrid.ts index c2da182..30c8ba7 100644 --- a/src/components/AppGrid.ts +++ b/src/components/AppGrid.ts @@ -14,52 +14,26 @@ export class AppGrid extends LitElement { name: string; }[] = []; - override connectedCallback() { - super.connectedCallback(); - this.style.setProperty('--icons-count', this.apps.length.toString()); - } - static override styles = [ css` :host { display: grid; grid-template-columns: 80px; justify-content: space-around; - gap: 28px; - padding: 42px 30px; + gap: 20px; + padding: 30px; margin-top: 10px; - --stagger-delay: calc(var(--animation-duration) * 2 / var(--icons-count)); - + @media (min-width: 500px) { grid-template-columns: repeat(2, 80px); - grid-auto-rows: minmax(120px, auto); } @media (min-width: 768px) { grid-template-columns: repeat(3, 80px); - gap: 32px 42px; } @media (min-width: 1024px) { grid-template-columns: repeat(4, 80px); - grid-auto-flow: dense; - } - } - - arx-app-icon { - opacity: 0; - transform: translateY(20px) scale(0.8); - animation: float-in var(--transition) forwards; - } - - @keyframes float-in { - 0% { - opacity: 0; - transform: translateY(20px) scale(0.8); - } - 100% { - opacity: 1; - transform: translateY(0) scale(1); } } `, @@ -69,13 +43,12 @@ export class AppGrid extends LitElement { return html` ${map( this.apps, - (app, index) => html` + (app) => html` `, )} diff --git a/src/components/AppIcon.ts b/src/components/AppIcon.ts index 72438d5..30f6990 100644 --- a/src/components/AppIcon.ts +++ b/src/components/AppIcon.ts @@ -2,7 +2,6 @@ import { LitElement, css, html } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import '@components/EveLink'; -import { ifDefined } from 'lit/directives/if-defined.js'; import { when } from 'lit/directives/when.js'; @customElement('arx-app-icon') @@ -19,56 +18,43 @@ export class AppIcon extends LitElement { @property() name = 'App'; - @property({ type: Boolean }) - small = false; - - @property({ type: Boolean }) - selected = false; - private iconElement?: HTMLElement; static override styles = [ css` :host { display: flex; - --shadow-opacity: 0.2; - --hover-lift: -6px; - --tap-scale: 0.92; + --animation-speed: 0.25s; } .app-icon { display: flex; flex-direction: column; align-items: center; - gap: 10px; + gap: 8px; text-decoration: none; - padding: 8px; + padding: 6px; border-radius: 18px; - transition: transform var(--transition); - position: relative; - will-change: transform; - perspective: 800px; + transition: transform var(--animation-speed) + cubic-bezier(0.175, 0.885, 0.32, 1.275); } .app-icon:hover { - transform: translateY(var(--hover-lift)); + transform: translateY(-2px); } .icon { width: 96px; height: 96px; border-radius: 24px; - box-shadow: 0 3px 8px rgba(0, 0, 0, var(--shadow-opacity)); + box-shadow: 0 3px 8px rgba(0, 0, 0, 0.12); display: flex; justify-content: center; align-items: center; border: 1px solid rgba(255, 255, 255, 0.2); overflow: hidden; position: relative; - transition: - transform var(--overshoot-transition), - box-shadow var(--overshoot-transition); - transform-style: preserve-3d; + transition: all var(--animation-speed) ease-out; &::before { content: ""; position: absolute; @@ -80,7 +66,7 @@ export class AppIcon extends LitElement { ); pointer-events: none; opacity: 1; - transition: opacity var(--transition); + transition: opacity var(--animation-speed) ease-out; } &::after { @@ -88,14 +74,13 @@ export class AppIcon extends LitElement { position: absolute; inset: 0; background: linear-gradient( - var(--gradient-angle, 145deg), - rgba(255, 255, 255, 0.35) 10%, - rgba(255, 255, 255, 0) 70% + var(--gradient-angle), + rgba(255, 255, 255, 0.25) 20%, + rgba(255, 255, 255, 0) 60% ); pointer-events: none; opacity: 0; - transition: opacity var(--undershoot-transition); - z-index: 1; + transition: opacity var(--animation-speed) ease-out; } &:hover::before { @@ -107,26 +92,17 @@ export class AppIcon extends LitElement { } } - :host([small]) .icon { - width: 64px; - height: 64px; - border-radius: 12px; - } - .icon-svg { color: white; filter: drop-shadow( - calc(cos(var(--gradient-angle, 145deg)) * 3px) - calc(sin(var(--gradient-angle, 145deg)) * 3px) - rgba(0, 0, 0, 0.25) + calc(cos(var(--gradient-angle)) * 2px) + calc(sin(var(--gradient-angle)) * 2px) rgba(0, 0, 0, 0.2) ); display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; - transition: transform var(--overshoot-transition); - z-index: 2; } .app-name { @@ -138,53 +114,16 @@ export class AppIcon extends LitElement { color: var(--color-base-content); white-space: nowrap; text-decoration: none; - transition: all var(--transition); - transform: translateZ(0); - opacity: 0.85; - } - - :host([selected]) .app-name { - color: var(--color-primary-content); - } - - :host([small]) .app-name { - font-size: 14px; - margin-top: 2px; + transition: all var(--animation-speed) ease-out; } .app-icon:hover .icon { - transform: scale(1.05) translateZ(10px) rotateX(var(--rotate-x, 0deg)) rotateY(var(--rotate-y, 0deg)); - box-shadow: - 0 10px 20px -5px rgba(0, 0, 0, calc(var(--shadow-opacity) * 1.5)), - 0 0 0 1px rgba(255, 255, 255, 0.15); - } - - :host([small]) .app-icon:hover .icon { - transform: scale(1.05) translateZ(5px) rotateX(var(--rotate-x, 0deg)) rotateY(var(--rotate-y, 0deg)); - } - - .app-icon:hover .app-name { - opacity: 1; - transform: translateY(2px) scale(1.02); - } - - .app-icon:hover .icon-svg { - transform: scale(1.08) translateZ(15px); - } - - :host([small]) .app-icon:hover .icon-svg { - transform: scale(1.08) translateZ(8px); + transform: scale(1.08); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25); } .app-icon:active .icon { - transform: scale(var(--tap-scale)) translateZ(0); - box-shadow: 0 2px 5px rgba(0, 0, 0, calc(var(--shadow-opacity) * 0.8)); - transition: all var(--transition); - } - - .app-icon:active .app-name { - transform: translateY(0) scale(0.98); - transition: all var(--transition); + transform: scale(0.96); } `, ]; @@ -193,7 +132,6 @@ export class AppIcon extends LitElement { this.iconElement = this.shadowRoot?.querySelector('.icon') as HTMLElement; if (this.iconElement) { this.iconElement.addEventListener('mousemove', this.handleMouseMove); - this.iconElement.addEventListener('mouseleave', this.handleMouseLeave); } } @@ -201,7 +139,6 @@ export class AppIcon extends LitElement { super.disconnectedCallback(); if (this.iconElement) { this.iconElement.removeEventListener('mousemove', this.handleMouseMove); - this.iconElement.removeEventListener('mouseleave', this.handleMouseLeave); } } @@ -216,32 +153,7 @@ export class AppIcon extends LitElement { const dy = e.clientY - centerY; const angle = Math.atan2(dy, dx) * (180 / Math.PI); - const maxTilt = 20; - const percentX = (e.clientX - rect.left) / rect.width - 0.5; - const percentY = (e.clientY - rect.top) / rect.height - 0.5; - - const tiltX = -percentY * maxTilt * 1.2; - const tiltY = percentX * maxTilt; - this.iconElement.style.setProperty('--gradient-angle', `${angle}deg`); - this.iconElement.style.setProperty('--rotate-x', `${tiltX}deg`); - this.iconElement.style.setProperty('--rotate-y', `${tiltY}deg`); - }; - - handleMouseLeave = () => { - if (!this.iconElement) return; - - this.iconElement.style.transition = 'transform var(--transition)'; - this.iconElement.style.setProperty('--rotate-x', '0deg'); - this.iconElement.style.setProperty('--rotate-y', '0deg'); - - this.iconElement.addEventListener( - 'transitionend', - () => { - this.iconElement!.style.transition = ''; - }, - { once: true }, - ); }; override render() { @@ -250,13 +162,12 @@ export class AppIcon extends LitElement {
${when( this.icon, - () => - html``, + () => html``, )}
${this.name} diff --git a/src/components/Calendar/CalendarEventDialog.ts b/src/components/Calendar/CalendarEventDialog.ts index e655369..b2bfcae 100644 --- a/src/components/Calendar/CalendarEventDialog.ts +++ b/src/components/Calendar/CalendarEventDialog.ts @@ -1,13 +1,11 @@ import { LitElement, css, html } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { type Ref, createRef, ref } from 'lit/directives/ref.js'; import { when } from 'lit/directives/when.js'; import '@components/General/Button'; import { StyledInput } from '@components/General/Input'; import { StyledTextarea } from '@components/General/Textarea'; import { StyledToggle } from '@components/General/Toggle'; -import type { EveDialog } from '../General/Dialog'; interface InputEvent extends Event { detail: { @@ -20,8 +18,6 @@ export class CalendarEventDialog extends LitElement { @property({ type: Boolean }) open = false; - dialogRef: Ref = createRef(); - @state() private newEvent = { title: '', @@ -53,8 +49,7 @@ export class CalendarEventDialog extends LitElement { `; private handleClose() { - this.dialogRef.value?.close(false); - this.dispatchEvent(new CustomEvent('close', { bubbles: false })); + this.dispatchEvent(new CustomEvent('close')); } private handleInputChange(e: Event) { @@ -82,7 +77,7 @@ export class CalendarEventDialog extends LitElement { if (!this.open) return html``; return html` - + ) { - if (changedProps.has('open')) { - if (this.open) this.show(); - else this.close(); + if (changedProps.has('open') && this.open) { + this._previousFocus = document.activeElement as HTMLElement; + // Focus the dialog container after rendering + setTimeout(() => { + const container = this.shadowRoot?.querySelector('.dialog-container') as HTMLElement; + if (container) container.focus(); + }, 50); + } else if (changedProps.has('open') && !this.open && this._previousFocus) { + this._previousFocus.focus(); } } @@ -139,36 +129,24 @@ export class EveDialog extends LitElement { } private _handleOverlayClick(e: MouseEvent) { - if (this.closeOnOverlayClick && e.target === e.currentTarget) this.close(); + if (this.closeOnOverlayClick && e.target === e.currentTarget) { + this.close(); + } } show() { this.open = true; - this.style.display = 'block'; - this.previousScrollTop = this.rootWindow?.scrollTop ?? 0; - this.style.height = `${this.rootWindow!.clientHeight * 2}px`; // this is a hack to prevent the overlay background from showing through - this.rootWindow?.style.setProperty('overflow', 'hidden', 'important'); - this.rootWindow?.scrollTo({ - top: 0, - behavior: 'smooth', - }); } - close(triggerEvent = true) { + close() { this.open = false; - this.style.display = 'none'; - this.rootWindow?.style.setProperty('overflow', 'auto', 'important'); - this.rootWindow?.scrollTo({ - top: this.previousScrollTop, - behavior: 'smooth', - }); - if (triggerEvent) this.dispatchEvent(new CustomEvent('close')); + this.dispatchEvent(new CustomEvent('close')); } override render() { return html`
diff --git a/src/components/Header.ts b/src/components/Header.ts index 2ef9272..e8745c9 100644 --- a/src/components/Header.ts +++ b/src/components/Header.ts @@ -35,6 +35,10 @@ export class Header extends LitElement { header { background: var(--color-primary); backdrop-filter: blur(10px); + border: var(--border) solid var(--color-primary-content); + box-shadow: calc(var(--depth) * 4px) calc(var(--depth) * 4px) + calc(var(--depth) * 8px) + oklch(from var(--color-base-content) l c h / 0.2); height: var(--font-2xl, 3rem); font-size: var(--font-md, 1rem); transition: all 0.3s ease; diff --git a/src/components/NostrAvatar.ts b/src/components/NostrAvatar.ts index caad32d..fbd43d3 100644 --- a/src/components/NostrAvatar.ts +++ b/src/components/NostrAvatar.ts @@ -1,8 +1,8 @@ -import defaultAvatar from '@assets/default-avatar.png'; import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; import { LitElement, css, html } from 'lit-element'; import { customElement, property } from 'lit/decorators.js'; type AvatarSize = 'short' | 'medium' | 'large' | 'huge'; +import defaultAvatar from '@/default-avatar.png'; @customElement('arx-nostr-avatar') export class ArxNostrAvatar extends LitElement { diff --git a/src/components/Sidebar.ts b/src/components/Sidebar.ts deleted file mode 100644 index 253f7a1..0000000 --- a/src/components/Sidebar.ts +++ /dev/null @@ -1,267 +0,0 @@ -import defaultAvatar from '@assets/default-avatar.png'; -import logo from '@assets/logo.png'; -import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; -import { LitElement, css, html } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { map } from 'lit/directives/map.js'; - -@customElement('arx-sidebar') -export default class Sidebar extends LitElement { - @property({ type: String }) - currentPath = ''; - - @property({ type: String }) - userNpub = ''; - - @property({ type: Object }) - userProfile: NDKUserProfile | undefined = undefined; - - @property({ type: Array }) - apps = [ - { - id: 1, - href: 'beacon', - name: 'Beacon', - color: '#FF8C00', - icon: 'fa-solid:sun', - }, - { - id: 2, - href: 'arbor', - name: 'Arbor', - color: '#FF4040', - icon: 'fa-solid:tree', - }, - { - id: 3, - href: 'wallet', - name: 'Wallet', - color: '#1E90FF', - icon: 'fa-solid:spa', - }, - { - id: 4, - href: 'settings', - name: 'Settings', - color: '#7B68EE', - icon: 'fa-solid:tools', - }, - ]; - - static override styles = css` - :host { - overflow-x: hidden; - background: var(--color-base-200); - padding: 0 0 1.5rem 0; - display: flex; - flex-direction: column; - align-items: center; - overflow-y: overlay; - scrollbar-width: none; - position: relative; - height: 100%; - } - - ::-webkit-scrollbar { - width: 4px; - height: 4px; - background: transparent; - } - - ::-webkit-scrollbar-track { - background: transparent; - margin: 3px; - } - - ::-webkit-scrollbar-thumb { - background: rgba(100, 100, 100, 0.4); - border-radius: 10px; - transition: all 0.3s ease; - } - - ::-webkit-scrollbar-thumb:hover { - background: rgba(100, 100, 100, 0.7); - } - - :host:hover { - scrollbar-color: rgba(100, 100, 100, 0.4) transparent; - } - - :host::after { - content: ''; - position: absolute; - right: 0; - top: 0; - width: 10px; - height: 100%; - opacity: 0; - pointer-events: none; - background: linear-gradient(to right, transparent, rgba(0, 0, 0, 0.03)); - transition: opacity 0.3s ease; - } - - :host:hover::after { - opacity: 1; - } - - .app-icon-small { - margin-bottom: 1.5rem; - width: 80px; - } - - .logo { - height: 64px; - margin-bottom: 1.5rem; - cursor: pointer; - transition: transform 0.2s ease, filter 0.3s ease; - border-radius: var(--radius-field); - padding: 8px; - background: none; - filter: - drop-shadow(0 0 2px rgba(0, 0, 0, 1)) - drop-shadow(0 0 1px rgba(255, 255, 255, 1)); - } - - .logo-container { - width: 100%; - background: var(--color-accent); - display: flex; - justify-content: center; - padding: 12px 0; - margin-bottom: 1.5rem; - position: relative; - } - - .logo-container::after { - content: ''; - position: absolute; - bottom: -5px; - left: 0; - right: 0; - height: 6px; - background: rgba(0, 0, 0, 0.08); - border-radius: 50%; - filter: blur(3px); - } - - .logo-container .logo { - margin-bottom: 0; - transform: translateY(0); - } - - .logo:hover { - transform: translateY(-2px) scale(1.02); - filter: - drop-shadow(0 0 3px rgba(0, 0, 0, 0.8)) - drop-shadow(0 0 2px rgba(255, 255, 255, 0.6)); - } - - .logo:active { - transform: translateY(1px) scale(0.98); - filter: - drop-shadow(0 0 1px rgba(0, 0, 0, 0.6)); - transition-duration: 0.1s; - } - - .app-icon-small.active { - transform: scale(1.15); - position: relative; - z-index: 10; - } - - .app-icon-small.active::before { - content: ''; - position: absolute; - top: -8px; - left: -8px; - right: -8px; - bottom: -8px; - background: var(--color-accent); - z-index: -1; - } - - .sidebar-item { - position: relative; - margin-bottom: 1.5rem; - transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - } - - .sidebar-item:hover { - transform: translateY(-2px); - } - - .profile-avatar { - width: 64px; - height: 64px; - border-radius: 50%; - object-fit: cover; - transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - border: 2px solid var(--color-base-300); - } - - .profile-avatar.active { - border-color: var(--color-primary); - transform: scale(1.15); - box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15); - } - - .profile-item { - margin-bottom: 1.5rem; - transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - display: flex; - justify-content: center; - } - - .profile-item:hover .profile-avatar { - transform: translateY(-2px) scale(1.05); - } - `; - - private handleLogoClick() { - this.dispatchEvent(new CustomEvent('navigate', { detail: 'home' })); - } - - override render() { - const activePath = this.currentPath.split('/')[0]; - - return html` - - ${map( - this.apps, - (app) => html` - - `, - )} -
- - `; - } -} diff --git a/src/default-avatar.png b/src/default-avatar.png new file mode 100644 index 0000000..02e81ef Binary files /dev/null and b/src/default-avatar.png differ diff --git a/src/electron/main.ts b/src/electron/main.ts index 14a0d67..c2eb3d8 100644 --- a/src/electron/main.ts +++ b/src/electron/main.ts @@ -38,11 +38,9 @@ ipcMain.handle('relay:status', () => { function createWindow(): void { const mainWindow = new BrowserWindow({ - width: 1366, + width: 1024, height: 768, show: false, - minWidth: 1366, - minHeight: 768, autoHideMenuBar: true, webPreferences: { preload: path.join(__dirname, '../preload/preload.mjs'), diff --git a/src/main.ts b/src/main.ts index af68c9c..45d1d50 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,13 @@ -import '@components/Breadcrumbs'; -import '@components/ErrorView'; -import '@components/Header'; -import '@components/LoadingView'; -import '@components/NostrAvatar'; -import '@components/NostrProfile'; -import '@routes/router'; -import type EveRouter from '@routes/router'; import './style.css'; +import '@components/ErrorView'; +import '@components/NostrAvatar'; +import '@components/LoadingView'; +import '@components/NostrProfile'; +import '@components/Breadcrumbs'; +import '@components/Header'; +import '@routes/router'; +import '@components/LoadingView'; +import type EveRouter from '@routes/router'; function checkRelayUp() { return new Promise((resolve, reject) => { diff --git a/src/routes/Home.ts b/src/routes/Home.ts index 929dddf..081c5a7 100644 --- a/src/routes/Home.ts +++ b/src/routes/Home.ts @@ -193,7 +193,7 @@ export class Home extends LitElement {
diff --git a/src/routes/Settings.ts b/src/routes/Settings.ts index ec13bab..ab245d3 100644 --- a/src/routes/Settings.ts +++ b/src/routes/Settings.ts @@ -1,5 +1,5 @@ +import defaultAvatar from '@/default-avatar.png'; import { getSigner, getUserProfile, ndk } from '@/ndk'; -import defaultAvatar from '@assets/default-avatar.png'; import type { ArxInputChangeEvent } from '@components/General/Input'; import { NDKEvent, type NDKUserProfile } from '@nostr-dev-kit/ndk'; import { LitElement, css, html } from 'lit'; @@ -62,7 +62,6 @@ export class EveSettings extends LitElement { @state() private profile: NDKUserProfile | undefined; @state() private error: string | undefined; @state() private darkMode = false; - @state() private pageTransitions = true; @state() private relayStatus: { running: boolean; pid: number | null; logs: string[] } = { running: false, pid: null, @@ -78,7 +77,6 @@ export class EveSettings extends LitElement { try { this.profile = await getUserProfile(); this.darkMode = localStorage.getItem('darkMode') === 'true'; - this.pageTransitions = localStorage.getItem('pageTransitions') !== 'false'; this.updateRelayStatus(); this.loading = false; } catch (err) { @@ -119,12 +117,6 @@ export class EveSettings extends LitElement { document.body.classList.toggle('dark', this.darkMode); } - private togglePageTransitions() { - this.pageTransitions = !this.pageTransitions; - localStorage.setItem('pageTransitions', this.pageTransitions.toString()); - location.reload(); - } - private reset() { if (!confirm('Are you sure you want to reset the app?')) return; localStorage.clear(); @@ -141,17 +133,12 @@ export class EveSettings extends LitElement { return html` - + this.toggleDarkMode()} > - this.togglePageTransitions()} - > ${when( diff --git a/src/routes/router.ts b/src/routes/router.ts index 51410f4..82cd92c 100644 --- a/src/routes/router.ts +++ b/src/routes/router.ts @@ -1,5 +1,4 @@ import '@components/InitialSetup'; -import '@components/Sidebar'; import '@routes/404Page'; import '@routes/Arbor/Home'; import '@routes/Arbor/NewPost'; @@ -11,14 +10,10 @@ import '@routes/Profile'; import '@routes/Settings'; import '@routes/Wallet'; -import { getNpub, getUserProfile } from '@/ndk'; -import type { NDKUserProfile } from '@nostr-dev-kit/ndk'; import { spread } from '@open-wc/lit-helpers'; import { LitElement, css } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import { keyed } from 'lit/directives/keyed.js'; -import { type Ref, createRef, ref } from 'lit/directives/ref.js'; -import { when } from 'lit/directives/when.js'; import { type StaticValue, html, literal } from 'lit/static-html.js'; export interface RouteParams { @@ -29,6 +24,7 @@ interface Route { pattern: string; params: RouteParams; component: StaticValue; + // component: typeof LitElement | ((params: RouteParams) => typeof LitElement); title?: string; meta?: Record; } @@ -94,34 +90,17 @@ export default class EveRouter extends LitElement { @state() private currentIndex = -1; - @state() - private isTransitioning = false; - @property() public ccnSetup = false; - windowContentRef: Ref = createRef(); - pageTransitions = true; - private beforeEachGuards: ((to: Route, from: Route | null) => boolean)[] = []; private afterEachHooks: ((to: Route, from: Route | null) => void)[] = []; - @state() - private userProfile: NDKUserProfile | undefined = undefined; - - @state() - private userNpub = ''; - static override styles = css` :host { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; + height: 100vh; display: grid; grid-template-rows: auto 1fr; - grid-template-columns: 100px 1fr; overflow: hidden; } @@ -145,34 +124,9 @@ export default class EveRouter extends LitElement { ::-webkit-scrollbar-thumb:hover { background: var(--color-neutral); } - + .window { overflow: auto; - grid-column: 2; - grid-row: 2; - position: relative; - } - - .window::after { - content: ''; - position: absolute; - right: 0; - top: 0; - width: 10px; - height: 100%; - opacity: 0; - pointer-events: none; - background: linear-gradient(to right, transparent, rgba(0, 0, 0, 0.03)); - transition: opacity 0.3s ease; - } - - .window:hover::after { - opacity: 1; - } - - arx-sidebar { - grid-column: 1; - grid-row: 1 / span 2; } .window-content { @@ -181,58 +135,22 @@ export default class EveRouter extends LitElement { height: 100%; margin: 0 auto; padding: 1rem; - opacity: 1; - transform-origin: left center; - transform: perspective(1200px) translateX(0); - transition: var(--transition); - backface-visibility: hidden; - filter: blur(0px); - } - - .window-content::after { - content: ''; - position: absolute; - top: 0; - right: 0; - width: 4px; - height: 100%; - opacity: 0; - transition: var(--transition); - } - - .window-content.transitioning { - overflow: hidden; - transform: perspective(1200px) translateX(50vw); - filter: blur(50px); - } - - .window-content.transitioning::after { - opacity: 1; } .hide-overflow { overflow: hidden; } - - arx-header { - grid-column: 2; - grid-row: 1; - } `; constructor() { super(); this.initializeRouter(); - this.pageTransitions = localStorage.getItem('pageTransitions') !== 'false'; if (this.ccnSetup) window.relay.start(localStorage.getItem('encryption_key')!); } override connectedCallback(): void { super.connectedCallback(); this.setupEventListeners(); - if (this.ccnSetup) { - this.loadUserProfile(); - } } override disconnectedCallback(): void { @@ -253,11 +171,11 @@ export default class EveRouter extends LitElement { window.addEventListener('popstate', this.handlePopState.bind(this)); } - private async handleHashChange(): Promise { + private handleHashChange(): void { const newPath = this.currentPath; if (newPath !== this.history[this.currentIndex]) { - await this.requestUpdateWithTransition(); this.updateHistory(newPath); + this.requestUpdate(); } } @@ -334,7 +252,7 @@ export default class EveRouter extends LitElement { const canProceed = this.beforeEachGuards.every((guard) => guard(to, from)); if (canProceed) { - await this.requestUpdateWithTransition(); + this.requestUpdate(); for (const hook of this.afterEachHooks) { hook(to, from); } @@ -345,25 +263,6 @@ export default class EveRouter extends LitElement { } } - async requestUpdateWithTransition(): Promise { - if (!this.windowContentRef.value) return this.requestUpdate(); - if (!this.pageTransitions) return this.requestUpdate(); - this.isTransitioning = true; - this.requestUpdate(); - - await new Promise((resolve) => { - this.windowContentRef.value!.addEventListener( - 'transitionend', - () => { - this.isTransitioning = false; - resolve(true); - }, - { once: true }, - ); - }); - this.requestUpdate(); - } - goBack(): void { if (this.currentIndex > 0) { this.currentIndex--; @@ -384,7 +283,7 @@ export default class EveRouter extends LitElement { renderSetup() { return html` -
+
this.finishSetup()} @@ -394,25 +293,9 @@ export default class EveRouter extends LitElement { `; } - async loadUserProfile() { - try { - this.userNpub = await getNpub(); - this.userProfile = await getUserProfile(); - } catch (error) { - console.error('Failed to load user profile:', error); - } - } - override render() { if (!this.ccnSetup) return this.renderSetup(); - return html` - this.navigate(e.detail)} - > 0} ?canGoForward=${this.currentIndex < this.history.length - 1} @@ -423,14 +306,10 @@ export default class EveRouter extends LitElement { title="Eve" >
-
- ${when( - this.isTransitioning, - () => html``, - () => - keyed( - this.currentRoute.params, - html` +
+ ${keyed( + this.currentRoute.params, + html` <${this.currentRoute.component} ${spread(this.currentRoute.params)} path=${this.currentPath} @@ -439,7 +318,6 @@ export default class EveRouter extends LitElement { @go-forward=${this.goForward} > `, - ), )}
diff --git a/src/style.css b/src/style.css index a66b6de..cee2999 100644 --- a/src/style.css +++ b/src/style.css @@ -6,13 +6,8 @@ --space-sm: clamp(1rem, 1.5vw, 1.5rem); --space-md: clamp(2rem, 3vw, 3rem); - --undershoot-curve: cubic-bezier(0.38, 0, 0.618, 0.88); - --animation-curve: cubic-bezier(0.18, 0, 0.618, 1); - --overshoot-curve: cubic-bezier(0.38, 0, 0.618, 1.12); - --animation-duration: 275ms; - --transition: var(--animation-duration) var(--animation-curve); - --overshoot-transition: calc(var(--animation-duration) * 1.2) var(--overshoot-curve); - --undershoot-transition: calc(var(--animation-duration) * 0.8) var(--undershoot-curve); + --animation-curve: cubic-bezier(0.68, -0.55, 0.265, 1.55); + --transition: 0.3s var(--animation-curve); --color-base-100: oklch(98% 0.016 73.684); --color-base-200: oklch(95% 0.038 75.164);