mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-13 20:36:35 +00:00
Gallery: Make sidebar collapsible + more tweaks (#11104)
This commit is contained in:
parent
a67799a670
commit
63c113f78d
@ -17,25 +17,33 @@ require("./entry-html.js");
|
||||
require("./rollup.js");
|
||||
|
||||
gulp.task("gather-gallery-demos", async function gatherDemos() {
|
||||
const files = await fs.promises.readdir(
|
||||
path.resolve(paths.gallery_dir, "src/demos")
|
||||
);
|
||||
const demoDir = path.resolve(paths.gallery_dir, "src/demos");
|
||||
const files = await fs.promises.readdir(demoDir);
|
||||
|
||||
const galleryBuild = path.resolve(paths.gallery_dir, "build");
|
||||
fs.mkdirSync(galleryBuild, { recursive: true });
|
||||
|
||||
let content = "export const DEMOS = {\n";
|
||||
|
||||
const processed = new Set();
|
||||
|
||||
for (const file of files) {
|
||||
if (!file.endsWith(".ts")) {
|
||||
let demoId = path.basename(
|
||||
file,
|
||||
file.endsWith(".ts") ? ".ts" : ".markdown"
|
||||
);
|
||||
|
||||
// Can be processed if we saw demo or description before.
|
||||
if (processed.has(demoId)) {
|
||||
continue;
|
||||
}
|
||||
const demoId = path.basename(file, ".ts");
|
||||
const descriptionFile = path.resolve(
|
||||
paths.gallery_dir,
|
||||
"src/demos",
|
||||
`${demoId}.markdown`
|
||||
);
|
||||
|
||||
processed.add(demoId);
|
||||
|
||||
const demoFile = path.resolve(demoDir, `${demoId}.ts`);
|
||||
|
||||
const descriptionFile = path.resolve(demoDir, `${demoId}.markdown`);
|
||||
const hasDemo = fs.existsSync(demoFile);
|
||||
const hasDescription = fs.existsSync(descriptionFile);
|
||||
if (hasDescription) {
|
||||
const descriptionContent = fs.readFileSync(descriptionFile, "utf-8");
|
||||
@ -55,7 +63,8 @@ gulp.task("gather-gallery-demos", async function gatherDemos() {
|
||||
? `description: () => import("${descriptionPath}").then(m => m.default),`
|
||||
: ""
|
||||
}
|
||||
load: () => import("${demoPath}")
|
||||
${hasDemo ? `load: () => import("${demoPath}")` : ""}
|
||||
|
||||
},\n`;
|
||||
}
|
||||
|
||||
@ -84,7 +93,17 @@ gulp.task(
|
||||
),
|
||||
"copy-static-gallery",
|
||||
"gen-index-gallery-dev",
|
||||
env.useRollup() ? "rollup-dev-server-gallery" : "webpack-dev-server-gallery"
|
||||
gulp.parallel(
|
||||
env.useRollup()
|
||||
? "rollup-dev-server-gallery"
|
||||
: "webpack-dev-server-gallery",
|
||||
async function watchMarkdownFiles() {
|
||||
gulp.watch(
|
||||
path.resolve(paths.gallery_dir, "src/demos/*.markdown"),
|
||||
gulp.series("gather-gallery-demos")
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
|
8
gallery/src/demos/demo-introduction.markdown
Normal file
8
gallery/src/demos/demo-introduction.markdown
Normal file
@ -0,0 +1,8 @@
|
||||
Lovelace has many different cards. Each card allows the user to tell
|
||||
a different story about what is going on in their house. These cards
|
||||
are very customizable, as no household is the same.
|
||||
|
||||
This gallery helps our developers and designers to see all the
|
||||
different states that each card can be in.
|
||||
|
||||
Check [the Lovelace documentation](https://www.home-assistant.io/lovelace) for instructions on how to get started with Lovelace.
|
@ -1,43 +0,0 @@
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-markdown";
|
||||
|
||||
@customElement("demo-introduction")
|
||||
export class DemoIntroduction extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-card header="Welcome!">
|
||||
<div class="card-content">
|
||||
<ha-markdown
|
||||
.content=${`
|
||||
Lovelace has many different cards. Each card allows the user to tell
|
||||
a different story about what is going on in their house. These cards
|
||||
are very customizable, as no household is the same.
|
||||
|
||||
This gallery helps our developers and designers to see all the
|
||||
different states that each card can be in.
|
||||
|
||||
Check [the Lovelace documentation](https://www.home-assistant.io/lovelace) for instructions on how to get started with Lovelace.
|
||||
`}
|
||||
></ha-markdown>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
ha-card {
|
||||
max-width: 600px;
|
||||
margin: 24px auto;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"demo-introduction": DemoIntroduction;
|
||||
}
|
||||
}
|
@ -4,55 +4,13 @@ import "@material/mwc-top-app-bar-fixed";
|
||||
import { html, css, LitElement, PropertyValues } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { until } from "lit/directives/until";
|
||||
import "../../src/components/ha-card";
|
||||
import "../../src/components/ha-icon-button";
|
||||
import "../../src/managers/notification-manager";
|
||||
import { haStyle } from "../../src/resources/styles";
|
||||
// eslint-disable-next-line import/extensions
|
||||
import { DEMOS } from "../build/import-demos";
|
||||
import { dynamicElement } from "../../src/common/dom/dynamic-element-directive";
|
||||
|
||||
const DEMOS_GROUPED: {
|
||||
header?: string;
|
||||
demos?: string[];
|
||||
demoStart?: string;
|
||||
}[] = [
|
||||
{
|
||||
demos: ["introduction"],
|
||||
},
|
||||
{
|
||||
header: "Lovelace",
|
||||
demoStart: "hui-",
|
||||
},
|
||||
{
|
||||
header: "Automation",
|
||||
demoStart: "automation-",
|
||||
},
|
||||
{
|
||||
header: "Rest",
|
||||
demoStart: "",
|
||||
},
|
||||
];
|
||||
|
||||
const demosToProcess = new Set(Object.keys(DEMOS));
|
||||
|
||||
for (const group of Object.values(DEMOS_GROUPED)) {
|
||||
if (group.demos) {
|
||||
for (const demo of group.demos) {
|
||||
demosToProcess.delete(demo);
|
||||
}
|
||||
}
|
||||
if (!group.demos) {
|
||||
group.demos = [];
|
||||
}
|
||||
if (group.demoStart !== undefined) {
|
||||
for (const demo of demosToProcess) {
|
||||
if (demo.startsWith(group.demoStart)) {
|
||||
group.demos.push(demo);
|
||||
demosToProcess.delete(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import { SIDEBAR } from "./sidebar";
|
||||
|
||||
const FAKE_HASS = {
|
||||
// Just enough for computeRTL for notification-manager
|
||||
@ -65,7 +23,7 @@ const FAKE_HASS = {
|
||||
@customElement("ha-gallery")
|
||||
class HaGallery extends LitElement {
|
||||
@property() private _demo =
|
||||
document.location.hash.substring(1) || DEMOS_GROUPED[0].demos![0];
|
||||
document.location.hash.substring(1) || SIDEBAR[0].demos![0];
|
||||
|
||||
@query("notification-manager")
|
||||
private _notifications!: HTMLElementTagNameMap["notification-manager"];
|
||||
@ -73,23 +31,51 @@ class HaGallery extends LitElement {
|
||||
@query("mwc-drawer")
|
||||
private _drawer!: HTMLElementTagNameMap["mwc-drawer"];
|
||||
|
||||
private _narrow = window.matchMedia("(max-width: 600px)").matches;
|
||||
|
||||
render() {
|
||||
const sidebar: unknown[] = [];
|
||||
|
||||
for (const group of SIDEBAR) {
|
||||
let sectionOpen = false;
|
||||
const links: unknown[] = [];
|
||||
|
||||
for (const demo of group.demos!) {
|
||||
const active = this._demo === demo;
|
||||
if (active) {
|
||||
sectionOpen = true;
|
||||
}
|
||||
|
||||
links.push(html`
|
||||
<a ?active=${active} href=${`#${demo}`}
|
||||
>${group.demoStart === undefined
|
||||
? demo
|
||||
: demo.substring(group.demoStart.length)}</a
|
||||
>
|
||||
`);
|
||||
}
|
||||
|
||||
sidebar.push(
|
||||
group.header
|
||||
? html`
|
||||
<details ?open=${sectionOpen}>
|
||||
<summary class="section">${group.header}</summary>
|
||||
${links}
|
||||
</details>
|
||||
`
|
||||
: links
|
||||
);
|
||||
}
|
||||
|
||||
return html`
|
||||
<mwc-drawer open hasHeader type="dismissible">
|
||||
<mwc-drawer
|
||||
hasHeader
|
||||
.open=${!this._narrow}
|
||||
.type=${this._narrow ? "modal" : "dismissible"}
|
||||
>
|
||||
<span slot="title">Home Assistant Design</span>
|
||||
<!-- <span slot="subtitle">subtitle</span> -->
|
||||
<div class="sidebar">
|
||||
${DEMOS_GROUPED.map(
|
||||
(group) => html`
|
||||
${group.header
|
||||
? html`<p class="section">${group.header}</p>`
|
||||
: ""}
|
||||
${group.demos!.map((demo) =>
|
||||
this._renderDemo(demo, group.demoStart)
|
||||
)}
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
<div class="sidebar">${sidebar}</div>
|
||||
<div slot="appContent">
|
||||
<mwc-top-app-bar-fixed>
|
||||
<ha-icon-button
|
||||
@ -106,7 +92,7 @@ class HaGallery extends LitElement {
|
||||
${until(
|
||||
DEMOS[this._demo].description().then(
|
||||
(content) => html`
|
||||
<ha-card .header=${this._demo}>
|
||||
<ha-card>
|
||||
<div class="card-content">${content}</div>
|
||||
</ha-card>
|
||||
`
|
||||
@ -126,21 +112,12 @@ class HaGallery extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderDemo(demo: string, demoStart?: string) {
|
||||
return html`
|
||||
<a ?active=${this._demo === demo} href=${`#${demo}`}
|
||||
>${demoStart === undefined ? demo : demo.substring(demoStart.length)}</a
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
firstUpdated(changedProps: PropertyValues) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
this.addEventListener("show-notification", (ev) =>
|
||||
this._notifications.showDialog({ message: ev.detail.message })
|
||||
);
|
||||
|
||||
this.addEventListener("alert-dismissed-clicked", () =>
|
||||
this._notifications.showDialog({ message: "Alert dismissed clicked" })
|
||||
);
|
||||
@ -156,12 +133,15 @@ class HaGallery extends LitElement {
|
||||
|
||||
window.addEventListener("hashchange", () => {
|
||||
this._demo = document.location.hash.substring(1);
|
||||
if (this._narrow) {
|
||||
this._drawer.open = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updated(changedProps: PropertyValues) {
|
||||
super.updated(changedProps);
|
||||
if (changedProps.has("_demo") && this._demo) {
|
||||
if (changedProps.has("_demo") && DEMOS[this._demo].load) {
|
||||
DEMOS[this._demo].load();
|
||||
}
|
||||
}
|
||||
@ -179,16 +159,18 @@ class HaGallery extends LitElement {
|
||||
-moz-user-select: initial;
|
||||
}
|
||||
|
||||
.section {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.sidebar p {
|
||||
margin: 1em 12px;
|
||||
.sidebar details {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.sidebar summary {
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.sidebar a {
|
||||
|
69
gallery/src/sidebar.ts
Normal file
69
gallery/src/sidebar.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { DEMOS } from "../build/import-demos";
|
||||
|
||||
export const SIDEBAR: SidebarSection[] = [
|
||||
{
|
||||
demos: ["introduction"],
|
||||
},
|
||||
|
||||
{
|
||||
// Each section has a header
|
||||
header: "Lovelace",
|
||||
// Specify demos to make sure they are put on top.
|
||||
demos: [],
|
||||
// Add a demoStart to automatically gather demos based on their name
|
||||
demoStart: "hui-",
|
||||
},
|
||||
{
|
||||
header: "Automation",
|
||||
demoStart: "automation-",
|
||||
},
|
||||
{
|
||||
header: "Components",
|
||||
demos: [
|
||||
"ha-alert",
|
||||
"ha-bar",
|
||||
"ha-chips",
|
||||
"ha-faded",
|
||||
"ha-form",
|
||||
"ha-label-badge",
|
||||
"ha-selector",
|
||||
],
|
||||
},
|
||||
{
|
||||
header: "More Info",
|
||||
demoStart: "more-info-",
|
||||
},
|
||||
{
|
||||
header: "Rest",
|
||||
demoStart: "", // empty string matches all.
|
||||
},
|
||||
];
|
||||
|
||||
interface SidebarSection {
|
||||
header?: string;
|
||||
demos?: string[];
|
||||
demoStart?: string;
|
||||
}
|
||||
|
||||
const demosToProcess = new Set(Object.keys(DEMOS));
|
||||
|
||||
for (const group of Object.values(SIDEBAR)) {
|
||||
// Any pre-defined groups will not be sorted.
|
||||
if (group.demos) {
|
||||
for (const demo of group.demos) {
|
||||
demosToProcess.delete(demo);
|
||||
}
|
||||
} else {
|
||||
group.demos = [];
|
||||
}
|
||||
}
|
||||
for (const group of Object.values(SIDEBAR)) {
|
||||
if (group.demoStart !== undefined) {
|
||||
for (const demo of demosToProcess) {
|
||||
if (demo.startsWith(group.demoStart)) {
|
||||
group.demos!.push(demo);
|
||||
demosToProcess.delete(demo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user