Skip to content

Commit 8602c24

Browse files
committed
Refacto details page to be more native
1 parent effb076 commit 8602c24

File tree

14 files changed

+1280
-1054
lines changed

14 files changed

+1280
-1054
lines changed

home-assistant-connect-zwa-2/install-portable.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
border-radius: 12px;
3838
padding: 20px;
3939
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
40-
margin-top: 20px;
40+
margin: 20px 0;
4141
}
4242

4343
.installer-card install-esphome-firmware {
@@ -77,8 +77,7 @@
7777
</div>
7878
<script type="module">
7979
import '../src/components/warning-card.js';
80-
81-
const isSerialUnavailable = !('serial' in navigator);
80+
import { isSerialUnavailable } from '../src/utils/const.ts';
8281

8382
if (isSerialUnavailable) {
8483
const installerContainer = document.getElementById(

home-assistant-connect-zwa-2/install.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
border-radius: 12px;
3939
padding: 20px;
4040
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
41-
margin-top: 20px;
41+
margin: 20px 0;
4242
}
4343

4444
.installer-card install-esp-bridge-firmware {
@@ -78,8 +78,7 @@
7878
</div>
7979
<script type="module">
8080
import '../src/components/warning-card.js';
81-
82-
const isSerialUnavailable = !('serial' in navigator);
81+
import { isSerialUnavailable } from '../src/utils/const.ts';
8382

8483
if (isSerialUnavailable) {
8584
const installerContainer = document.getElementById(

src/components/action-item.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { LitElement, css, html } from 'lit';
2+
import { customElement, property } from 'lit/decorators.js';
3+
4+
@customElement('action-item')
5+
export class ActionItem extends LitElement {
6+
@property({ type: String }) href = '';
7+
@property({ type: String }) icon = '';
8+
@property({ type: String, attribute: 'trailing-icon' }) trailingIcon = '';
9+
10+
static styles = css`
11+
:host {
12+
display: block;
13+
}
14+
15+
.action-item {
16+
display: grid;
17+
grid-template-columns: auto 1fr auto;
18+
align-items: center;
19+
gap: 16px;
20+
padding: 18px 16px;
21+
cursor: pointer;
22+
border-radius: 6px;
23+
}
24+
25+
.action-item:hover {
26+
background: var(--app-bg-secondary);
27+
}
28+
29+
.action-icon {
30+
width: 40px;
31+
height: 40px;
32+
border-radius: 50%;
33+
background: var(--app-category-bg);
34+
display: flex;
35+
align-items: center;
36+
justify-content: center;
37+
}
38+
39+
.icon-mask {
40+
width: 20px;
41+
height: 20px;
42+
background-color: var(--app-category-text);
43+
-webkit-mask: var(--icon-url) no-repeat center / contain;
44+
mask: var(--icon-url) no-repeat center / contain;
45+
}
46+
47+
.action-content {
48+
min-width: 0;
49+
}
50+
51+
.action-content ::slotted(h3),
52+
.action-content ::slotted([slot='title']) {
53+
margin: 0 0 6px 0;
54+
color: var(--app-text-primary);
55+
font-size: 1rem;
56+
font-weight: 600;
57+
}
58+
59+
.action-content ::slotted(p),
60+
.action-content ::slotted([slot='description']) {
61+
margin: 0;
62+
color: var(--app-text-secondary);
63+
font-size: 0.95rem;
64+
line-height: 1.45;
65+
}
66+
67+
.action-content ::slotted(.experimental) {
68+
color: #e78e21;
69+
}
70+
71+
.action-trailing svg {
72+
width: 16px;
73+
height: 16px;
74+
fill: var(--app-text-muted);
75+
}
76+
77+
.chevron-icon {
78+
color: var(--app-text-primary);
79+
width: 20px !important;
80+
height: 20px !important;
81+
}
82+
`;
83+
84+
private _handleClick() {
85+
const isExternal = this.href.startsWith('http');
86+
if (isExternal) {
87+
window.open(this.href, '_blank', 'noopener,noreferrer');
88+
return;
89+
}
90+
window.location.href = this.href;
91+
}
92+
93+
render() {
94+
return html`
95+
<div class="action-item" @click=${this._handleClick}>
96+
<div class="action-icon">
97+
<div class="icon-mask" style="--icon-url: url(${this.icon})"></div>
98+
</div>
99+
<div class="action-content">
100+
<slot></slot>
101+
</div>
102+
<div class="action-trailing">
103+
${this.trailingIcon
104+
? html`<svg
105+
xmlns="http://www.w3.org/2000/svg"
106+
viewBox="0 0 24 24"
107+
class="chevron-icon"
108+
>
109+
<path
110+
fill="currentColor"
111+
d="M12.6 12L8 7.4L9.4 6l6 6l-6 6L8 16.6z"
112+
/>
113+
</svg>`
114+
: html`<svg
115+
xmlns="http://www.w3.org/2000/svg"
116+
viewBox="0 0 448 512"
117+
>
118+
<path
119+
d="M320 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l82.7 0-201.4 201.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L448 109.3 448 192c0 17.7 14.3 32 32 32s32-14.3 32-32l0-160c0-17.7-14.3-32-32-32L320 0zM80 96C35.8 96 0 131.8 0 176L0 432c0 44.2 35.8 80 80 80l256 0c44.2 0 80-35.8 80-80l0-80c0-17.7-14.3-32-32-32s-32 14.3-32 32l0 80c0 8.8-7.2 16-16 16L80 448c-8.8 0-16-7.2-16-16l0-256c0-8.8 7.2-16 16-16l80 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L80 96z"
120+
/>
121+
</svg>`}
122+
</div>
123+
</div>
124+
`;
125+
}
126+
}
127+
128+
declare global {
129+
interface HTMLElementTagNameMap {
130+
'action-item': ActionItem;
131+
}
132+
}

0 commit comments

Comments
 (0)