Add catalog package
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
node_modules/
|
||||
dist/
|
||||
dist_*/
|
||||
dist_ts/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
.nogit/
|
||||
.playwright-mcp/
|
||||
*.log
|
||||
.DS_Store
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"@git.zone/cli": {
|
||||
"projectType": "wcc",
|
||||
"module": {
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "smarthome.exchange",
|
||||
"gitrepo": "catalog",
|
||||
"description": "Web component catalog for smarthome.exchange.",
|
||||
"npmPackagename": "@smarthome.exchange/catalog",
|
||||
"license": "MIT",
|
||||
"projectDomain": "smarthome.exchange",
|
||||
"keywords": [
|
||||
"smarthome.exchange",
|
||||
"web components",
|
||||
"home automation",
|
||||
"agents",
|
||||
"design system"
|
||||
]
|
||||
},
|
||||
"release": {
|
||||
"registries": [
|
||||
"https://verdaccio.lossless.digital",
|
||||
"https://registry.npmjs.org"
|
||||
],
|
||||
"accessLevel": "public"
|
||||
}
|
||||
},
|
||||
"@git.zone/tsbundle": {
|
||||
"bundles": [
|
||||
{
|
||||
"from": "./ts_web/index.ts",
|
||||
"to": "./dist_bundle/bundle.js",
|
||||
"outputMode": "bundle",
|
||||
"bundler": "esbuild",
|
||||
"production": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"@git.zone/tswatch": {
|
||||
"preset": "element"
|
||||
},
|
||||
"@ship.zone/szci": {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>smarthome.exchange catalog</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="./index.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,29 @@
|
||||
import * as deesWccTools from '@design.estate/dees-wcctools';
|
||||
import * as deesDomTools from '@design.estate/dees-domtools';
|
||||
|
||||
import * as elements from '../ts_web/elements/index.js';
|
||||
|
||||
const fullPageElementNames = new Set([
|
||||
'ShxLandingPage',
|
||||
'ShxConsoleShell',
|
||||
]);
|
||||
|
||||
deesWccTools.setupWccTools({
|
||||
sections: [
|
||||
{
|
||||
name: 'Full Pages',
|
||||
type: 'elements',
|
||||
items: elements,
|
||||
icon: 'web',
|
||||
filter: (nameArg: string) => fullPageElementNames.has(nameArg),
|
||||
},
|
||||
{
|
||||
name: 'Primitives',
|
||||
type: 'elements',
|
||||
items: elements,
|
||||
icon: 'category',
|
||||
filter: (nameArg: string) => nameArg.startsWith('Shx') && !fullPageElementNames.has(nameArg),
|
||||
},
|
||||
],
|
||||
});
|
||||
deesDomTools.elementBasic.setup();
|
||||
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "@smarthome.exchange/catalog",
|
||||
"version": "0.1.0",
|
||||
"private": false,
|
||||
"description": "Web component catalog for smarthome.exchange.",
|
||||
"exports": {
|
||||
".": "./dist_ts_web/index.js"
|
||||
},
|
||||
"main": "dist_ts_web/index.js",
|
||||
"typings": "dist_ts_web/index.d.ts",
|
||||
"type": "module",
|
||||
"author": "Task Venture Capital GmbH",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "pnpm run build",
|
||||
"build": "tsbuild tsfolders --allowimplicitany && tsbundle",
|
||||
"watch": "tswatch",
|
||||
"buildDocs": "tsdoc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@design.estate/dees-catalog": "^3.81.0",
|
||||
"@design.estate/dees-domtools": "^2.5.6",
|
||||
"@design.estate/dees-element": "^2.2.4",
|
||||
"@design.estate/dees-wcctools": "^3.9.0",
|
||||
"lucide": "^1.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^4.4.0",
|
||||
"@git.zone/tsbundle": "^2.10.1",
|
||||
"@git.zone/tswatch": "^3.3.3",
|
||||
"@push.rocks/projectinfo": "^5.1.0",
|
||||
"@types/node": "^25.6.0"
|
||||
},
|
||||
"files": [
|
||||
"ts_web/**/*",
|
||||
"dist/**/*",
|
||||
"dist_*/**/*",
|
||||
"dist_ts_web/**/*",
|
||||
"assets/**/*",
|
||||
"html/**/*",
|
||||
"license",
|
||||
"readme.md",
|
||||
"changelog.md"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@code.foss.global:29419/smarthome.exchange/catalog.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://code.foss.global/smarthome.exchange/catalog/issues"
|
||||
},
|
||||
"homepage": "https://code.foss.global/smarthome.exchange/catalog#readme",
|
||||
"browserslist": [
|
||||
"last 1 chrome versions"
|
||||
],
|
||||
"keywords": [
|
||||
"smarthome.exchange",
|
||||
"catalog",
|
||||
"web components",
|
||||
"home automation",
|
||||
"design system"
|
||||
],
|
||||
"packageManager": "pnpm@10.28.2"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# @smarthome.exchange/catalog
|
||||
|
||||
Web component catalog for smarthome.exchange landing, console, dashboard, and primitive UI components.
|
||||
@@ -0,0 +1,20 @@
|
||||
export const shxDemoAgents = [
|
||||
{ id: 'comfort', name: 'Comfort', role: 'Climate, light, ambience', color: '#f59e0b', mode: 'auto', latest: 'Holding Office at 22.4C during Mira\'s call' },
|
||||
{ id: 'sentinel', name: 'Sentinel', role: 'Locks, cameras, presence', color: '#ef4444', mode: 'ask', latest: 'Front door unlocked for Jonah' },
|
||||
{ id: 'watt', name: 'Watt', role: 'Energy, solar, EV, appliances', color: '#22c55e', mode: 'ask', latest: 'Proposed EV charging during solar peak' },
|
||||
{ id: 'dawn', name: 'Dawn', role: 'Wake, wind-down, daily ritual', color: '#a78bfa', mode: 'auto', latest: 'Prepared evening wind-down' },
|
||||
{ id: 'echo', name: 'Echo', role: 'Audio, media, follow-me', color: '#60a5fa', mode: 'suggest', latest: 'Suggested dinner playlist' },
|
||||
{ id: 'steward', name: 'Steward', role: 'Errands, deliveries, household ops', color: '#f87171', mode: 'ask', latest: 'Laundry pickup reminder queued' },
|
||||
];
|
||||
|
||||
export const shxDemoDevices = [
|
||||
{ id: 'climate.office', name: 'Office Thermostat', room: 'Office', state: '22.4C hold', agent: 'comfort' },
|
||||
{ id: 'lock.front', name: 'Front Lock', room: 'Hall', state: 'unlocked', agent: 'sentinel' },
|
||||
{ id: 'energy.solar', name: 'Solar Inverter', room: 'Roof', state: '3.8 kW', agent: 'watt' },
|
||||
{ id: 'light.living.floor', name: 'Living Floor Lamp', room: 'Living', state: 'on 65%', agent: 'comfort' },
|
||||
];
|
||||
|
||||
export const shxDemoApprovals = [
|
||||
{ id: 'approval:ev', agent: 'watt', title: 'Charge EV to 80%', reason: 'Solar surplus and tariff dip between 15:00 and 17:00.', confidence: 0.86 },
|
||||
{ id: 'approval:trash', agent: 'steward', title: 'Take out paper recycling', reason: 'Collection tomorrow at 06:00.', confidence: 0.71 },
|
||||
];
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './tokens.js';
|
||||
export * from './shx-badge.js';
|
||||
export * from './shx-button.js';
|
||||
export * from './shx-card.js';
|
||||
export * from './shx-icon.js';
|
||||
export * from './shx-console-shell.js';
|
||||
export * from './shx-landing-page.js';
|
||||
@@ -0,0 +1,37 @@
|
||||
import { DeesElement, html, customElement, css } from '@design.estate/dees-element';
|
||||
import { shxElementStyles } from './tokens.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'shx-badge': ShxBadge;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('shx-badge')
|
||||
export class ShxBadge extends DeesElement {
|
||||
public static demo = () => html`<shx-badge>local-first</shx-badge>`;
|
||||
public static demoGroups = ['smarthome.exchange primitives'];
|
||||
|
||||
public static styles = [
|
||||
...shxElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 22px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid color-mix(in srgb, var(--shx-accent), transparent 70%);
|
||||
border-radius: 999px;
|
||||
background: var(--shx-accent-soft);
|
||||
color: var(--shx-accent);
|
||||
font: 600 11px/1 var(--shx-mono);
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`<slot></slot>`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { DeesElement, html, customElement, css } from '@design.estate/dees-element';
|
||||
import { shxElementStyles } from './tokens.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'shx-button': ShxButton;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('shx-button')
|
||||
export class ShxButton extends DeesElement {
|
||||
public static demo = () => html`<shx-button>Open console</shx-button>`;
|
||||
public static demoGroups = ['smarthome.exchange primitives'];
|
||||
|
||||
public static styles = [
|
||||
...shxElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 34px;
|
||||
padding: 0 14px;
|
||||
border: 1px solid var(--shx-accent);
|
||||
border-radius: 7px;
|
||||
background: var(--shx-accent);
|
||||
color: #fff;
|
||||
font: 600 13px/1 var(--shx-font);
|
||||
letter-spacing: -0.01em;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`<button part="button"><slot></slot></button>`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { DeesElement, html, customElement, css } from '@design.estate/dees-element';
|
||||
import { shxElementStyles } from './tokens.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'shx-card': ShxCard;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('shx-card')
|
||||
export class ShxCard extends DeesElement {
|
||||
public static demo = () => html`<shx-card><strong>Card</strong><p>Reusable panel frame.</p></shx-card>`;
|
||||
public static demoGroups = ['smarthome.exchange primitives'];
|
||||
|
||||
public static styles = [
|
||||
...shxElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.card {
|
||||
border: 1px solid var(--shx-border);
|
||||
border-radius: var(--shx-radius);
|
||||
background: var(--shx-card);
|
||||
box-shadow: 0 16px 50px rgba(0,0,0,0.18);
|
||||
overflow: hidden;
|
||||
}
|
||||
.body {
|
||||
padding: 18px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`<div class="card"><div class="body"><slot></slot></div></div>`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
import { DeesElement, html, customElement, css } from '@design.estate/dees-element';
|
||||
import { shxDemoAgents, shxDemoApprovals, shxDemoDevices } from '../demo/demo-data.js';
|
||||
import { shxElementStyles } from './tokens.js';
|
||||
import './shx-badge.js';
|
||||
import './shx-card.js';
|
||||
import './shx-icon.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'shx-console-shell': ShxConsoleShell;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('shx-console-shell')
|
||||
export class ShxConsoleShell extends DeesElement {
|
||||
public static demo = () => html`<shx-console-shell></shx-console-shell>`;
|
||||
public static demoGroups = ['smarthome.exchange full pages'];
|
||||
|
||||
public static styles = [
|
||||
...shxElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
min-height: 100vh;
|
||||
background: var(--shx-bg);
|
||||
color: var(--shx-fg);
|
||||
}
|
||||
.shell {
|
||||
display: grid;
|
||||
grid-template-columns: 230px 1fr;
|
||||
min-height: 100vh;
|
||||
}
|
||||
aside {
|
||||
border-right: 1px solid var(--shx-border-soft);
|
||||
background: var(--shx-card);
|
||||
padding: 16px;
|
||||
}
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
font: 800 14px/1 var(--shx-display);
|
||||
}
|
||||
.nav {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
.nav div {
|
||||
padding: 8px 10px;
|
||||
border-radius: 7px;
|
||||
color: var(--shx-fg-3);
|
||||
font-size: 13px;
|
||||
}
|
||||
.nav div:first-child {
|
||||
background: var(--shx-accent-soft);
|
||||
color: var(--shx-accent);
|
||||
}
|
||||
main {
|
||||
padding: 18px;
|
||||
}
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
font: 800 24px/1 var(--shx-display);
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 0.8fr;
|
||||
gap: 14px;
|
||||
}
|
||||
.list {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
.row {
|
||||
display: grid;
|
||||
grid-template-columns: 10px 1fr auto;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--shx-border-soft);
|
||||
border-radius: 8px;
|
||||
background: var(--shx-card-2);
|
||||
}
|
||||
.dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.name {
|
||||
font-weight: 700;
|
||||
}
|
||||
.sub {
|
||||
margin-top: 2px;
|
||||
color: var(--shx-fg-3);
|
||||
font-size: 12px;
|
||||
}
|
||||
@media (max-width: 860px) {
|
||||
.shell, .grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
aside {
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--shx-border-soft);
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`
|
||||
<div class="shell">
|
||||
<aside>
|
||||
<div class="brand"><shx-icon></shx-icon> smarthome.exchange</div>
|
||||
<div class="nav">
|
||||
<div>Now</div>
|
||||
<div>Agents</div>
|
||||
<div>Schedule</div>
|
||||
<div>Devices</div>
|
||||
<div>Activity</div>
|
||||
</div>
|
||||
</aside>
|
||||
<main>
|
||||
<div class="top">
|
||||
<h1>Birch Lane</h1>
|
||||
<shx-badge>hub online · 12ms</shx-badge>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<shx-card>
|
||||
<h2>Agents</h2>
|
||||
<div class="list">
|
||||
${shxDemoAgents.map((agentArg) => html`
|
||||
<div class="row">
|
||||
<span class="dot" style="background:${agentArg.color}"></span>
|
||||
<div><div class="name">${agentArg.name}</div><div class="sub">${agentArg.latest}</div></div>
|
||||
<shx-badge>${agentArg.mode}</shx-badge>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
</shx-card>
|
||||
<div class="list">
|
||||
<shx-card>
|
||||
<h2>Pending approvals</h2>
|
||||
<div class="list">
|
||||
${shxDemoApprovals.map((approvalArg) => html`
|
||||
<div class="row">
|
||||
<span class="dot" style="background:var(--shx-amber)"></span>
|
||||
<div><div class="name">${approvalArg.title}</div><div class="sub">${approvalArg.reason}</div></div>
|
||||
<shx-badge>${Math.round(approvalArg.confidence * 100)}%</shx-badge>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
</shx-card>
|
||||
<shx-card>
|
||||
<h2>Devices</h2>
|
||||
<div class="list">
|
||||
${shxDemoDevices.map((deviceArg) => html`
|
||||
<div class="row">
|
||||
<span class="dot" style="background:var(--shx-green)"></span>
|
||||
<div><div class="name">${deviceArg.name}</div><div class="sub">${deviceArg.room} · ${deviceArg.state}</div></div>
|
||||
<shx-badge>${deviceArg.agent}</shx-badge>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
</shx-card>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { DeesElement, html, customElement, css } from '@design.estate/dees-element';
|
||||
import { shxElementStyles } from './tokens.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'shx-icon': ShxIcon;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('shx-icon')
|
||||
export class ShxIcon extends DeesElement {
|
||||
public static demo = () => html`<shx-icon></shx-icon>`;
|
||||
public static demoGroups = ['smarthome.exchange primitives'];
|
||||
|
||||
public static styles = [
|
||||
...shxElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: inline-flex;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: var(--shx-accent);
|
||||
}
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M4 9.5 12 3l8 6.5V20a1 1 0 0 1-1 1h-5v-7h-4v7H5a1 1 0 0 1-1-1V9.5Z"></path>
|
||||
<path d="M9 21v-7h6v7"></path>
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
import { DeesElement, html, customElement, css } from '@design.estate/dees-element';
|
||||
import { shxElementStyles } from './tokens.js';
|
||||
import './shx-badge.js';
|
||||
import './shx-button.js';
|
||||
import './shx-icon.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'shx-landing-page': ShxLandingPage;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('shx-landing-page')
|
||||
export class ShxLandingPage extends DeesElement {
|
||||
public static demo = () => html`<shx-landing-page></shx-landing-page>`;
|
||||
public static demoGroups = ['smarthome.exchange full pages'];
|
||||
|
||||
public static styles = [
|
||||
...shxElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
min-height: 100vh;
|
||||
background: radial-gradient(circle at 80% 10%, rgba(59,130,246,0.18), transparent 30%), var(--shx-bg);
|
||||
color: var(--shx-fg);
|
||||
}
|
||||
.wrap {
|
||||
max-width: 1180px;
|
||||
margin: 0 auto;
|
||||
padding: 0 28px;
|
||||
}
|
||||
nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 18px;
|
||||
min-height: 64px;
|
||||
border-bottom: 1px solid var(--shx-border-soft);
|
||||
}
|
||||
.brand {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
font: 800 15px/1 var(--shx-display);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
.links {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
margin-left: auto;
|
||||
color: var(--shx-fg-3);
|
||||
font-size: 13px;
|
||||
}
|
||||
.hero {
|
||||
display: grid;
|
||||
grid-template-columns: 1.05fr 0.95fr;
|
||||
gap: 44px;
|
||||
align-items: center;
|
||||
padding: 88px 0 72px;
|
||||
}
|
||||
h1 {
|
||||
margin: 18px 0 18px;
|
||||
max-width: 720px;
|
||||
font: 800 clamp(44px, 7vw, 78px)/0.95 var(--shx-display);
|
||||
letter-spacing: -0.06em;
|
||||
}
|
||||
h1 em, h2 em {
|
||||
color: var(--shx-accent);
|
||||
font-style: normal;
|
||||
}
|
||||
.lede {
|
||||
max-width: 680px;
|
||||
color: var(--shx-fg-2);
|
||||
font-size: 18px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.cta {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
.panel {
|
||||
border: 1px solid var(--shx-border);
|
||||
border-radius: 16px;
|
||||
background: color-mix(in srgb, var(--shx-card), transparent 4%);
|
||||
box-shadow: 0 24px 70px rgba(0,0,0,0.34);
|
||||
overflow: hidden;
|
||||
}
|
||||
.panel-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 14px;
|
||||
border-bottom: 1px solid var(--shx-border-soft);
|
||||
color: var(--shx-fg-3);
|
||||
font: 500 11px/1 var(--shx-mono);
|
||||
}
|
||||
.panel-body {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 16px;
|
||||
}
|
||||
.tool-row {
|
||||
display: grid;
|
||||
grid-template-columns: 12px 1fr auto;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--shx-border-soft);
|
||||
border-radius: 9px;
|
||||
background: var(--shx-card-2);
|
||||
font-size: 13px;
|
||||
}
|
||||
.dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--shx-green);
|
||||
box-shadow: 0 0 12px var(--shx-green);
|
||||
}
|
||||
section {
|
||||
padding: 64px 0;
|
||||
border-top: 1px solid var(--shx-border-soft);
|
||||
}
|
||||
h2 {
|
||||
margin: 0 0 16px;
|
||||
max-width: 760px;
|
||||
font: 800 40px/1.05 var(--shx-display);
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
.grid3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 14px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
.mini {
|
||||
min-height: 220px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--shx-border);
|
||||
border-radius: 14px;
|
||||
background: var(--shx-card);
|
||||
}
|
||||
.mini strong {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
font: 800 20px/1.1 var(--shx-display);
|
||||
}
|
||||
.mini p {
|
||||
color: var(--shx-fg-3);
|
||||
line-height: 1.55;
|
||||
}
|
||||
@media (max-width: 860px) {
|
||||
.hero, .grid3 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.links {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render() {
|
||||
return html`
|
||||
<div class="wrap">
|
||||
<nav>
|
||||
<div class="brand"><shx-icon></shx-icon> smarthome.exchange</div>
|
||||
<div class="links">
|
||||
<span>Tools</span>
|
||||
<span>Agents</span>
|
||||
<span>Automations</span>
|
||||
<span>Open source</span>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="hero">
|
||||
<div>
|
||||
<shx-badge>local-first home OS</shx-badge>
|
||||
<h1>An open home OS, <em>spoken in the language of agents.</em></h1>
|
||||
<p class="lede">Every device, sensor, and routine becomes a typed tool: discoverable, permission-scoped, audit-logged, and callable by Claude, a local model, or your own TypeScript agent.</p>
|
||||
<div class="cta">
|
||||
<shx-button>Open console</shx-button>
|
||||
<shx-badge>BYO LLM</shx-badge>
|
||||
<shx-badge>MCP-native</shx-badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="panel-head"><span>birch-lane.local/mcp</span><span>live</span></div>
|
||||
<div class="panel-body">
|
||||
<div class="tool-row"><span class="dot"></span><span>devices.climate.office.hold</span><shx-badge>auto</shx-badge></div>
|
||||
<div class="tool-row"><span class="dot"></span><span>agents.watt.decide</span><shx-badge>ask</shx-badge></div>
|
||||
<div class="tool-row"><span class="dot"></span><span>devices.lock.front.set</span><shx-badge>approval</shx-badge></div>
|
||||
<div class="tool-row"><span class="dot"></span><span>audit.receipts.append</span><shx-badge>signed</shx-badge></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section>
|
||||
<h2>Three primitives. <em>That is the whole platform.</em></h2>
|
||||
<div class="grid3">
|
||||
<div class="mini"><strong>Typed devices</strong><p>Matter, Zigbee, Z-Wave, Thread, MQTT, HomeKit, ESPHome, and Home Assistant devices become callable tools.</p></div>
|
||||
<div class="mini"><strong>Scoped agents</strong><p>Agents receive revocable scopes and explicit modes: auto, ask, or suggest. No ambient access.</p></div>
|
||||
<div class="mini"><strong>Audit receipts</strong><p>Every effectful call creates a receipt with caller, scope, input summary, output summary, and undo intent.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { css, cssManager } from '@design.estate/dees-element';
|
||||
|
||||
export const shxBaseStyles = css`
|
||||
:host {
|
||||
--shx-bg: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
|
||||
--shx-bg-2: ${cssManager.bdTheme('#f4f4f5', '#111111')};
|
||||
--shx-card: ${cssManager.bdTheme('#ffffff', '#121212')};
|
||||
--shx-card-2: ${cssManager.bdTheme('#f8fafc', '#161616')};
|
||||
--shx-fg: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
|
||||
--shx-fg-2: ${cssManager.bdTheme('#3f3f46', '#d4d4d8')};
|
||||
--shx-fg-3: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||
--shx-fg-4: ${cssManager.bdTheme('#a1a1aa', '#525252')};
|
||||
--shx-border: ${cssManager.bdTheme('#e4e4e7', '#262626')};
|
||||
--shx-border-soft: ${cssManager.bdTheme('#f1f5f9', '#1c1c1c')};
|
||||
--shx-accent: ${cssManager.bdTheme('#0050b9', '#3b82f6')};
|
||||
--shx-accent-2: ${cssManager.bdTheme('#6e5be6', '#a78bfa')};
|
||||
--shx-accent-soft: ${cssManager.bdTheme('#e6effb', 'rgba(59,130,246,0.15)')};
|
||||
--shx-green: ${cssManager.bdTheme('#16a34a', '#4ade80')};
|
||||
--shx-amber: ${cssManager.bdTheme('#b45309', '#fbbf24')};
|
||||
--shx-red: ${cssManager.bdTheme('#dc2626', '#f87171')};
|
||||
--shx-radius: 10px;
|
||||
--shx-font: 'Geist', ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--shx-display: 'Plus Jakarta Sans', 'Geist', ui-sans-serif, system-ui, sans-serif;
|
||||
--shx-mono: 'Intel One Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
color: var(--shx-fg);
|
||||
font-family: var(--shx-font);
|
||||
font-feature-settings: 'cv11', 'tnum', 'cv05';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
:host([theme="dark"]),
|
||||
:host([dark]) {
|
||||
--shx-bg: #0a0a0a;
|
||||
--shx-bg-2: #111111;
|
||||
--shx-card: #121212;
|
||||
--shx-card-2: #161616;
|
||||
--shx-fg: #fafafa;
|
||||
--shx-fg-2: #d4d4d8;
|
||||
--shx-fg-3: #a1a1aa;
|
||||
--shx-fg-4: #525252;
|
||||
--shx-border: #262626;
|
||||
--shx-border-soft: #1c1c1c;
|
||||
--shx-accent: #3b82f6;
|
||||
--shx-accent-2: #a78bfa;
|
||||
--shx-accent-soft: rgba(59,130,246,0.15);
|
||||
--shx-green: #4ade80;
|
||||
--shx-amber: #fbbf24;
|
||||
--shx-red: #f87171;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
`;
|
||||
|
||||
export const shxElementStyles = [cssManager.defaultStyles, shxBaseStyles];
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './elements/index.js';
|
||||
export * from './demo/demo-data.js';
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user