Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3a6ef2f
Begin work on Common OS skeleton
gordonbrander Sep 26, 2024
af00def
Add common-ui
gordonbrander Sep 26, 2024
80f5713
Update sidebar
gordonbrander Sep 26, 2024
7c17261
Stub ooout some dummy items in sidebar
gordonbrander Sep 26, 2024
f11bb28
Add more scaffolding, incl scene layout
gordonbrander Sep 26, 2024
a1e0e13
Stub in buttons, change prefix to os-
gordonbrander Sep 26, 2024
f5ed90b
Stub in scrolling sidebar
gordonbrander Sep 26, 2024
87d94e3
Add icon button active state
gordonbrander Sep 26, 2024
e978a5e
Add gap to sidebar content items
gordonbrander Sep 26, 2024
bf51c59
Reworking font styles a bit
gordonbrander Sep 26, 2024
80d73b8
Add location pill
gordonbrander Sep 26, 2024
06680e4
Add Material Icon component
gordonbrander Sep 27, 2024
ab0d2bd
Fine-tune icon font
gordonbrander Sep 27, 2024
8db03a3
Add hover state to location
gordonbrander Sep 27, 2024
18f2992
Refine label styles and sidebar group spacing
gordonbrander Sep 27, 2024
b9ea9b3
Stub in sidebar states for os-scene
gordonbrander Sep 27, 2024
4c99db8
Wire up show/hide sidebar to button
gordonbrander Sep 27, 2024
3777fb7
Add activated property
gordonbrander Sep 30, 2024
3bc6a2d
Refine open/close animation
gordonbrander Sep 30, 2024
68f571d
Rename os-scene to os-chrome
gordonbrander Sep 30, 2024
db89ac3
Simplify CSS variable naming convention
gordonbrander Sep 30, 2024
e9e92b3
Allow specifying location title
gordonbrander Sep 30, 2024
4bc6d5d
Work around broken container queries vs slots
gordonbrander Oct 1, 2024
1db1fec
Remove unused import
gordonbrander Oct 1, 2024
d9a6597
Allow container to get wider
gordonbrander Oct 1, 2024
469ed75
Add CSS transition util
gordonbrander Oct 1, 2024
fe35698
Support modal sidebar with os-navstack
gordonbrander Oct 1, 2024
b67f4a3
Stub in os-fab
gordonbrander Oct 2, 2024
ad37c87
Add hover state to fab and bubbles
gordonbrander Oct 2, 2024
9bd5409
Add pinned charm group components
gordonbrander Oct 2, 2024
d101182
Add cursor-pointer to bubble
gordonbrander Oct 2, 2024
b44cfd7
Undock and overlap sidebar at small screen sizes
gordonbrander Oct 2, 2024
41264d9
Sidebar now supports splitscreen attr
gordonbrander Oct 3, 2024
2e173f3
Change sidebar attribute to wide
gordonbrander Oct 3, 2024
070f165
Add dialog component
gordonbrander Oct 3, 2024
0f333bb
Add dialog component
gordonbrander Oct 3, 2024
286e53c
Rename numbered vars for consistency
gordonbrander Oct 3, 2024
fd29437
Make icon sizeable
gordonbrander Oct 3, 2024
05dce26
Make AI icon sizeable
gordonbrander Oct 3, 2024
32cb071
Add charm chips and demo dialog box
gordonbrander Oct 3, 2024
496232a
Set cursor pointer on charm chip
gordonbrander Oct 3, 2024
0957b05
Set safe area for dialog left/right at small size
gordonbrander Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Undock and overlap sidebar at small screen sizes
  • Loading branch information
gordonbrander committed Oct 2, 2024
commit b44cfd74938cb2a45a39ee86a000a0444e5500c3
88 changes: 59 additions & 29 deletions typescript/packages/common-os-ui/src/components/os-chrome.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { LitElement, css, html } from "lit-element";
import { LitElement, PropertyValues, css, html } from "lit-element";
import { customElement, property } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import { base } from "../shared/styles.js";
import { breakpointLg, ResponsiveElement } from "./responsive-element.js";

/**
* Custom element representing the chrome (outer structure) of the application.
Expand All @@ -19,7 +20,7 @@ import { base } from "../shared/styles.js";
* @slot sidebar-toolbar - Additional elements to be placed in the sidebar toolbar.
*/
@customElement("os-chrome")
export class OsChrome extends LitElement {
export class OsChrome extends ResponsiveElement {
static override styles = [
base,
css`
Expand All @@ -31,14 +32,58 @@ export class OsChrome extends LitElement {
}

.chrome {
display: grid;
grid-template-columns: 1fr 0;
grid-template-areas: "main sidebar";
overflow: hidden;
display: block;
grid-template-columns: 1fr;
justify-items: stretch;
height: 100vh;
transition: grid var(--dur-md) var(--ease-out-cubic);
position: relative;
overflow: hidden;
/*
NOTE: prevents transition initial state bug. We trigger an update due to
responsive element ResizeObserver, which sets a breakpoint class to
work around bugs with container queries and slotted content.
Because this class is not present during the first microtask, the
initial property of the padding is 0, causing a transition on first
load. However, setting display none and then block when we add the
breakpoint class solves the issue, since the the intial value will
not be used for animation since the element is display none.
*/
display: none;

&.breakpoint {
display: block;
}

.chrome-main {
transition: padding-right var(--dur-lg) var(--ease-out-expo);
padding-right: 0;

:host([sidebar]) .breakpoint-lg & {
padding-right: var(--sidebar-width);
}
}

.chrome-sidebar {
background-color: var(--bg-2);
position: absolute;
right: 0;
top: 0;
height: 100vh;
transform: translateX(var(--sidebar-width));
transition: transform var(--dur-lg) var(--ease-out-expo);

:host([sidebar]) & {
transform: translateX(0);
}

.chrome-sidebar-inner {
display: block;
/* Set fixed width on inner element to prevent text reflow on
sidebar animation. */
width: var(--sidebar-width);
height: 100vh;
}
}
}

/** Container for absolute elements */
Expand Down Expand Up @@ -74,27 +119,6 @@ export class OsChrome extends LitElement {
}
}

.chrome-sidebar {
background-color: var(--bg-2);
grid-area: sidebar;
height: 100vh;

.chrome-sidebar-inner {
display: block;
/* Set fixed width on inner element to prevent text reflow on
sidebar animation. */
width: var(--sidebar-width);
height: 100vh;
}
}

/* Sidebar animation */
:host([sidebar]) {
.chrome {
grid-template-columns: 1fr var(--sidebar-width);
}
}

/* Half-and-half editor mode animation */
:host([state="split"]) {
.chrome {
Expand Down Expand Up @@ -123,8 +147,14 @@ export class OsChrome extends LitElement {
this.sidebar = !this.sidebar;
};

const classes = classMap({
chrome: true,
breakpoint: this.getObservedWidth() > 0,
"breakpoint-lg": this.getObservedWidth() >= breakpointLg + 480,
});

return html`
<div class="chrome" @sidebarclose="${onSidebarClose}">
<div class="${classes}" @sidebarclose="${onSidebarClose}">
<div class="chrome-overlay">
<os-fabgroup class="pin-br">
<os-bubble icon="add" text="Lorem ipsum dolor sit amet"></os-bubble>
Expand Down
20 changes: 12 additions & 8 deletions typescript/packages/common-os-ui/src/components/os-colgrid.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { css, html } from "lit-element";
import { customElement } from "lit/decorators.js";
import { base } from "../shared/styles.js";
import { ResponsiveElement } from "./responsive-element.js";
import {
ResponsiveElement,
breakpointLg,
breakpointMd,
} from "./responsive-element.js";

@customElement("os-colgrid")
export class OsColgrid extends ResponsiveElement {
Expand Down Expand Up @@ -31,13 +35,13 @@ export class OsColgrid extends ResponsiveElement {
];

#getSizeClass() {
switch (this.breakpoint()) {
case "lg":
return "colgrid-lg";
case "md":
return "colgrid-md";
default:
return "colgrid-sm";
const width = this.getObservedWidth();
if (width >= breakpointLg) {
return "colgrid-lg";
} else if (width >= breakpointMd) {
return "colgrid-md";
} else {
return "colgrid-sm";
}
}

Expand Down
13 changes: 6 additions & 7 deletions typescript/packages/common-os-ui/src/components/os-navstack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import {
setTransitions,
transition,
durationMd,
cubicBezierCss,
easeOutCubic,
easeOutExpo,
easeOutExpoCss,
easeOutCubicCss,
} from "../shared/animation.js";

@customElement("os-navstack")
Expand Down Expand Up @@ -83,15 +82,15 @@ export class OsNavstack extends LitElement {
transition({
property: "left",
duration: durationMd,
easing: cubicBezierCss(easeOutCubic),
value: `480px`,
easing: easeOutCubicCss,
to: `480px`,
}),
transition({
property: "opacity",
duration: durationMd,
delay: 100,
easing: cubicBezierCss(easeOutExpo),
value: `0`,
easing: easeOutExpoCss,
to: `0`,
}),
]);
panels.pop();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import { LitElement } from "lit";
import { state } from "lit/decorators.js";

export const breakpointForWidth = (width: number): String => {
if (width >= 800) {
return "lg";
} else if (width >= 600) {
return "md";
} else {
return "sm";
}
};
export const breakpointLg = 800;
export const breakpointMd = 600;

/**
* This element reacts to changes in its width using a resize observer,
Expand All @@ -27,12 +19,18 @@ export const breakpointForWidth = (width: number): String => {
*/
export class ResponsiveElement extends LitElement {
#resizeObserver: ResizeObserver;
@state() private _observedWidth: number = -1;
#observedWidth: number = -1;

constructor() {
super();
const isSelf = (entry: ResizeObserverEntry) => entry.target === this;
this.#resizeObserver = new ResizeObserver((entries) => {
this._observedWidth = entries.at(0)?.contentRect.width ?? -1;
const entry = entries.find(isSelf);
const observedWidth = entry?.contentRect.width ?? -1;
if (this.#observedWidth !== observedWidth) {
this.#observedWidth = observedWidth;
this.requestUpdate();
}
});
}

Expand All @@ -47,7 +45,7 @@ export class ResponsiveElement extends LitElement {
this.#resizeObserver.disconnect();
}

breakpoint() {
return breakpointForWidth(this._observedWidth);
getObservedWidth() {
return this.#observedWidth;
}
}
32 changes: 23 additions & 9 deletions typescript/packages/common-os-ui/src/shared/animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const slowable = (ms: number) => (slowAnimations ? 10000 : ms);

export const durationSm = 250;
export const durationMd = 350;
export const durationLg = 500;
export const durationLg = 350;

/** Create a promise for a timeout */
export const timeout = (ms: number): Promise<void> =>
Expand Down Expand Up @@ -39,29 +39,36 @@ export const easeOutExpo = cubicBezier(0.19, 1, 0.22, 1);
export const cubicBezierCss = ({ x1, y1, x2, y2 }: CubicBezier) =>
`cubic-bezier(${x1}, ${y1}, ${x2}, ${y2})`;

export const easeOutCubicCss = cubicBezierCss(easeOutCubic);
export const easeOutExpoCss = cubicBezierCss(easeOutExpo);

export type Transition = {
property: string;
duration: number;
delay: number;
easing: string;
value: string;
from?: string;
to: string;
};

export const transition = ({
property,
value,
duration = 0,
from,
to,
duration = durationMd,
delay = 0,
easing = "ease-out",
easing = easeOutCubicCss,
}: {
property: string;
value: string;
from?: any;
to: any;
duration?: number;
delay?: number;
easing?: string;
}): Transition => ({
property,
value,
from: from != null ? `${from}` : undefined,
to: `${to}`,
duration: slowable(duration),
easing,
delay,
Expand Down Expand Up @@ -92,11 +99,18 @@ export const setTransitions = async <E extends HTMLElement>(
transitions: Array<Transition>,
): Promise<E> => {
const fullDuration = fullTransitionDuration(transitions);
element.style.removeProperty("transition");
for (const t of transitions) {
if (t.from != null) {
element.style.setProperty(t.property, t.from);
}
}
await timeout(0);
element.style.transition = transitionsToCssRule(transitions);
for (const t of transitions) {
element.style.setProperty(t.property, t.value);
element.style.setProperty(t.property, t.to);
}
await timeout(fullDuration + 0.001);
await timeout(fullDuration);
element.style.removeProperty("transition");
return element;
};