feat(catalog): add admin dashboard components
This commit is contained in:
+1542
-565
File diff suppressed because it is too large
Load Diff
@@ -40,9 +40,15 @@ export class IdpButton extends DeesElement {
|
||||
@property({ type: String })
|
||||
public accessor icon = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor type: 'button' | 'submit' | 'reset' = 'button';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor disabled = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor loading = false;
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
@@ -101,7 +107,7 @@ export class IdpButton extends DeesElement {
|
||||
}
|
||||
.accent {
|
||||
background: var(--idp-accent);
|
||||
color: #fff;
|
||||
color: var(--idp-accent-fg);
|
||||
box-shadow: 0 4px 14px color-mix(in srgb, var(--idp-accent), transparent 64%);
|
||||
}
|
||||
.accent:hover:not(:disabled) {
|
||||
@@ -126,18 +132,33 @@ export class IdpButton extends DeesElement {
|
||||
}
|
||||
.destructive {
|
||||
background: var(--idp-destructive);
|
||||
color: #fff;
|
||||
color: var(--idp-accent-fg);
|
||||
}
|
||||
idp-icon {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.spinner {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
border: 2px solid currentColor;
|
||||
border-right-color: transparent;
|
||||
border-radius: 999px;
|
||||
animation: spin 700ms linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<button class="${this.variant} ${this.size}" ?disabled=${this.disabled} part="button">
|
||||
${this.icon ? html`<idp-icon name=${this.icon as any} size="14"></idp-icon>` : html``}
|
||||
<button class="${this.variant} ${this.size}" type=${this.type} ?disabled=${this.disabled || this.loading} part="button">
|
||||
${this.loading
|
||||
? html`<span class="spinner" aria-hidden="true"></span>`
|
||||
: this.icon ? html`<idp-icon name=${this.icon as any} size="14"></idp-icon>` : html``}
|
||||
<slot></slot>
|
||||
</button>
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
|
||||
import { idpElementStyles } from './tokens.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'idp-checkbox': IdpCheckbox;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('idp-checkbox')
|
||||
export class IdpCheckbox extends DeesElement {
|
||||
public static demo = () => html`<idp-checkbox label="I agree to the terms" required></idp-checkbox>`;
|
||||
public static demoGroups = ['idp.global v3 primitives'];
|
||||
|
||||
@property({ type: String })
|
||||
public accessor label = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor name = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor key = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor value = 'on';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor hint = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor error = '';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor checked = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor required = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor disabled = false;
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
label {
|
||||
display: grid;
|
||||
grid-template-columns: 18px 1fr;
|
||||
gap: 10px;
|
||||
align-items: start;
|
||||
color: var(--idp-fg);
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
cursor: pointer;
|
||||
}
|
||||
input {
|
||||
appearance: none;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: 0;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 5px;
|
||||
background: var(--idp-card);
|
||||
cursor: pointer;
|
||||
transition: background 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
|
||||
}
|
||||
input:checked {
|
||||
border-color: var(--idp-accent);
|
||||
background: var(--idp-accent);
|
||||
box-shadow: inset 0 0 0 3px var(--idp-card);
|
||||
}
|
||||
input:focus-visible {
|
||||
outline: 2px solid color-mix(in srgb, var(--idp-accent), transparent 68%);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
input[aria-invalid='true'] {
|
||||
border-color: var(--idp-destructive);
|
||||
}
|
||||
input:disabled,
|
||||
:host([disabled]) label {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.55;
|
||||
}
|
||||
.copy {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
}
|
||||
.hint,
|
||||
.error {
|
||||
color: var(--idp-muted-fg);
|
||||
font-size: 12px;
|
||||
}
|
||||
.error {
|
||||
color: var(--idp-destructive);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public validate() {
|
||||
if (this.required && !this.checked) {
|
||||
this.error = `${this.label || this.name || 'This field'} is required.`;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.error = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
private handleChange(eventArg: Event) {
|
||||
this.checked = (eventArg.target as HTMLInputElement).checked;
|
||||
if (this.error) {
|
||||
this.validate();
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('idp-checkbox-change', {
|
||||
detail: { name: this.name || this.key, key: this.key || this.name, checked: this.checked, value: this.value },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
name=${this.name || this.key}
|
||||
value=${this.value}
|
||||
?checked=${this.checked}
|
||||
?required=${this.required}
|
||||
?disabled=${this.disabled}
|
||||
aria-invalid=${this.error ? 'true' : 'false'}
|
||||
@change=${this.handleChange}
|
||||
/>
|
||||
<span class="copy">
|
||||
<span>${this.label}</span>
|
||||
${this.error ? html`<span class="error">${this.error}</span>` : this.hint ? html`<span class="hint">${this.hint}</span>` : html``}
|
||||
</span>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { idpElementStyles } from './tokens.js';
|
||||
import './idp-badge.js';
|
||||
import './idp-button.js';
|
||||
import './idp-icon.js';
|
||||
import './idp-data-table.js';
|
||||
|
||||
type TDashboardStat = {
|
||||
label: string;
|
||||
@@ -24,7 +25,7 @@ declare global {
|
||||
|
||||
@customElement('idp-dashboard-window')
|
||||
export class IdpDashboardWindow extends DeesElement {
|
||||
public static demo = () => html`<idp-dashboard-window dark></idp-dashboard-window>`;
|
||||
public static demo = () => html`<idp-dashboard-window></idp-dashboard-window>`;
|
||||
public static demoGroups = ['idp.global v3 composed surfaces'];
|
||||
|
||||
public static styles = [
|
||||
@@ -139,7 +140,7 @@ export class IdpDashboardWindow extends DeesElement {
|
||||
place-items: center;
|
||||
border-radius: 4px;
|
||||
background: var(--idp-accent);
|
||||
color: #fff;
|
||||
color: var(--idp-accent-fg);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
@@ -340,51 +341,6 @@ export class IdpDashboardWindow extends DeesElement {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th, td {
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid var(--idp-border-soft);
|
||||
text-align: left;
|
||||
font-size: 12.5px;
|
||||
}
|
||||
th {
|
||||
color: color-mix(in srgb, var(--idp-muted-fg), transparent 35%);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.user {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.row-avatar {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 50%;
|
||||
background: var(--idp-card-2);
|
||||
color: var(--idp-accent-hover);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 9.5px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.row-name {
|
||||
color: var(--idp-fg);
|
||||
font-weight: 500;
|
||||
}
|
||||
.row-email, .dim {
|
||||
color: var(--idp-muted-fg);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 11px;
|
||||
}
|
||||
.feed-item {
|
||||
display: grid;
|
||||
grid-template-columns: 14px 1fr auto;
|
||||
@@ -450,9 +406,6 @@ export class IdpDashboardWindow extends DeesElement {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
th:nth-child(3), td:nth-child(3), th:nth-child(4), td:nth-child(4) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
@@ -522,8 +475,25 @@ export class IdpDashboardWindow extends DeesElement {
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
const approvalRows = this.approvals.map((rowArg) => ({
|
||||
cells: [
|
||||
html`
|
||||
<div class="identity-cell">
|
||||
<span class="identity-avatar">${rowArg[0].slice(0, 2).toUpperCase()}</span>
|
||||
<div>
|
||||
<div class="identity-primary">${rowArg[0]}</div>
|
||||
<div class="identity-secondary">${rowArg[1]}</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
rowArg[2],
|
||||
rowArg[3],
|
||||
html`<idp-badge variant=${rowArg[5] as any}>${rowArg[4]}</idp-badge>`,
|
||||
],
|
||||
}));
|
||||
|
||||
return html`
|
||||
<div class="dash" theme="dark">
|
||||
<div class="dash">
|
||||
<div class="chrome">
|
||||
<span class="tdot red"></span><span class="tdot yellow"></span><span class="tdot green"></span>
|
||||
<span class="url"><idp-icon name="lock" size="11" style="color: var(--idp-ok)"></idp-icon> console.idp.global / dashboard</span>
|
||||
@@ -561,22 +531,23 @@ export class IdpDashboardWindow extends DeesElement {
|
||||
${this.stats.map((statArg) => this.renderStat(statArg))}
|
||||
</div>
|
||||
<div class="grid">
|
||||
<section class="card">
|
||||
<div class="card-head"><span class="card-title">Recent approvals</span><idp-badge>142 total</idp-badge></div>
|
||||
<table>
|
||||
<thead><tr><th>User</th><th>Action</th><th>Device</th><th>Status</th></tr></thead>
|
||||
<tbody>
|
||||
${this.approvals.map((rowArg) => html`
|
||||
<tr>
|
||||
<td><div class="user"><span class="row-avatar">${rowArg[0].slice(0, 2).toUpperCase()}</span><div><div class="row-name">${rowArg[0]}</div><div class="row-email">${rowArg[1]}</div></div></div></td>
|
||||
<td>${rowArg[2]}</td>
|
||||
<td><span class="dim">${rowArg[3]}</span></td>
|
||||
<td><idp-badge variant=${rowArg[5] as any}>${rowArg[4]}</idp-badge></td>
|
||||
</tr>
|
||||
`)}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<idp-data-table
|
||||
title="Recent approvals"
|
||||
badge="142 total"
|
||||
selected-tab="all"
|
||||
.tabs=${[
|
||||
{ id: 'all', label: 'All' },
|
||||
{ id: 'pending', label: 'Pending' },
|
||||
{ id: 'denied', label: 'Denied' },
|
||||
]}
|
||||
.columns=${[
|
||||
{ label: 'User' },
|
||||
{ label: 'Action' },
|
||||
{ label: 'Device', mono: true, hideBelow: 'mobile' },
|
||||
{ label: 'Status' },
|
||||
]}
|
||||
.rows=${approvalRows}
|
||||
></idp-data-table>
|
||||
<section class="card">
|
||||
<div class="card-head"><span class="card-title">Cardano feed</span><idp-badge variant="accent"><span class="live-dot"></span>live</idp-badge></div>
|
||||
${this.feed.map((itemArg) => html`
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
|
||||
import { idpElementStyles } from './tokens.js';
|
||||
import './idp-badge.js';
|
||||
|
||||
export type TIdpDataTableCell = TemplateResult | string | number | null | undefined;
|
||||
|
||||
export interface IIdpDataTableColumn {
|
||||
label: string;
|
||||
width?: string;
|
||||
align?: 'left' | 'center' | 'right';
|
||||
mono?: boolean;
|
||||
hideBelow?: 'mobile' | 'tablet';
|
||||
}
|
||||
|
||||
export interface IIdpDataTableRow {
|
||||
id?: string;
|
||||
cells: TIdpDataTableCell[];
|
||||
}
|
||||
|
||||
export interface IIdpDataTableTab {
|
||||
id: string;
|
||||
label: string;
|
||||
count?: string | number;
|
||||
}
|
||||
|
||||
export interface IIdpDataTableTabSelectEventDetail {
|
||||
tabId: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'idp-data-table': IdpDataTable;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('idp-data-table')
|
||||
export class IdpDataTable extends DeesElement {
|
||||
public static demo = () => html`
|
||||
<idp-data-table
|
||||
title="Recent activity"
|
||||
badge="3 total"
|
||||
.columns=${[
|
||||
{ label: 'User' },
|
||||
{ label: 'Action' },
|
||||
{ label: 'Device', mono: true, hideBelow: 'mobile' },
|
||||
{ label: 'Status' },
|
||||
{ label: 'When', align: 'right', mono: true },
|
||||
]}
|
||||
.tabs=${[
|
||||
{ id: 'all', label: 'All' },
|
||||
{ id: 'pending', label: 'Pending' },
|
||||
{ id: 'denied', label: 'Denied' },
|
||||
]}
|
||||
selected-tab="all"
|
||||
.rows=${[
|
||||
{
|
||||
cells: [
|
||||
html`<div class="identity-cell"><span class="identity-avatar">EU</span><div><div class="identity-primary">Example User</div><div class="identity-secondary">user@example.com</div></div></div>`,
|
||||
'OAuth grant',
|
||||
'Desktop',
|
||||
html`<idp-badge variant="ok">approved</idp-badge>`,
|
||||
'2m ago',
|
||||
],
|
||||
},
|
||||
]}
|
||||
></idp-data-table>
|
||||
`;
|
||||
public static demoGroups = ['idp.global v3 primitives'];
|
||||
|
||||
@property({ type: String })
|
||||
public accessor title = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor subtitle = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor badge = '';
|
||||
|
||||
@property({ type: String, attribute: 'selected-tab' })
|
||||
public accessor selectedTab = '';
|
||||
|
||||
@property({ type: String, attribute: 'empty-title' })
|
||||
public accessor emptyTitle = 'No rows';
|
||||
|
||||
@property({ type: String, attribute: 'empty-description' })
|
||||
public accessor emptyDescription = 'There is no data to display yet.';
|
||||
|
||||
@property({ type: Array })
|
||||
public accessor columns: IIdpDataTableColumn[] = [];
|
||||
|
||||
@property({ type: Array })
|
||||
public accessor rows: IIdpDataTableRow[] = [];
|
||||
|
||||
@property({ type: Array })
|
||||
public accessor tabs: IIdpDataTableTab[] = [];
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.table-card {
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 8px;
|
||||
background: var(--idp-card);
|
||||
}
|
||||
.table-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--idp-border-soft);
|
||||
}
|
||||
.title-wrap {
|
||||
min-width: 0;
|
||||
}
|
||||
.title-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.title {
|
||||
color: var(--idp-fg);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.subtitle {
|
||||
margin-top: 2px;
|
||||
color: var(--idp-muted-fg);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
.count-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 2px 8px;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 999px;
|
||||
background: var(--idp-muted);
|
||||
color: var(--idp-muted-fg);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
line-height: 16px;
|
||||
}
|
||||
.tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
margin-left: auto;
|
||||
}
|
||||
.tab {
|
||||
padding: 4px 10px;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
color: var(--idp-muted-fg);
|
||||
cursor: pointer;
|
||||
font-family: var(--idp-font);
|
||||
font-size: 11px;
|
||||
}
|
||||
.tab:hover,
|
||||
.tab.active {
|
||||
background: var(--idp-bg-2);
|
||||
color: var(--idp-fg);
|
||||
}
|
||||
.table-scroll {
|
||||
overflow-x: auto;
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
border-bottom: 1px solid var(--idp-border-soft);
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
}
|
||||
th {
|
||||
padding: 9px 16px;
|
||||
background: var(--idp-muted);
|
||||
color: var(--idp-fg-3);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
white-space: nowrap;
|
||||
}
|
||||
td {
|
||||
padding: 10px 16px;
|
||||
color: var(--idp-fg-2);
|
||||
font-size: 12.5px;
|
||||
}
|
||||
tbody tr:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
tbody tr:hover td {
|
||||
background: var(--idp-bg-2);
|
||||
}
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
.mono-cell {
|
||||
color: var(--idp-muted-fg);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 11.5px;
|
||||
}
|
||||
.identity-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 190px;
|
||||
}
|
||||
.identity-avatar {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 999px;
|
||||
background: var(--idp-bg-2);
|
||||
color: var(--avatar-color, var(--idp-accent));
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 9.5px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.identity-primary {
|
||||
color: var(--idp-fg);
|
||||
font-size: 12.5px;
|
||||
font-weight: 500;
|
||||
}
|
||||
.identity-secondary,
|
||||
.cell-secondary {
|
||||
margin-top: 1px;
|
||||
color: var(--idp-muted-fg);
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
}
|
||||
.chip-row,
|
||||
.cell-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.cell-actions {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.table-action {
|
||||
min-height: 28px;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 7px;
|
||||
background: transparent;
|
||||
color: var(--idp-fg);
|
||||
cursor: pointer;
|
||||
font-family: var(--idp-font);
|
||||
font-size: 12px;
|
||||
}
|
||||
.table-action:hover {
|
||||
background: var(--idp-bg-2);
|
||||
}
|
||||
.table-action.destructive {
|
||||
border-color: var(--idp-error-border);
|
||||
color: var(--idp-error);
|
||||
}
|
||||
.table-action.primary {
|
||||
border-color: var(--idp-accent);
|
||||
background: var(--idp-accent);
|
||||
color: var(--idp-accent-fg);
|
||||
}
|
||||
.empty-state {
|
||||
padding: 32px 20px;
|
||||
color: var(--idp-muted-fg);
|
||||
text-align: center;
|
||||
}
|
||||
.empty-title {
|
||||
color: var(--idp-fg);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.empty-description {
|
||||
max-width: 420px;
|
||||
margin: 6px auto 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.hide-tablet {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
.table-head {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.tabs {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
}
|
||||
.hide-mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
private selectTab(tabIdArg: string) {
|
||||
this.selectedTab = tabIdArg;
|
||||
this.dispatchEvent(new CustomEvent<IIdpDataTableTabSelectEventDetail>('idp-data-table-tab-select', {
|
||||
detail: { tabId: tabIdArg },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
}
|
||||
|
||||
private columnClass(columnArg: IIdpDataTableColumn): string {
|
||||
const classes = [
|
||||
columnArg.align === 'center' ? 'align-center' : '',
|
||||
columnArg.align === 'right' ? 'align-right' : '',
|
||||
columnArg.hideBelow === 'mobile' ? 'hide-mobile' : '',
|
||||
columnArg.hideBelow === 'tablet' ? 'hide-tablet' : '',
|
||||
];
|
||||
return classes.filter(Boolean).join(' ');
|
||||
}
|
||||
|
||||
private renderCell(contentArg: TIdpDataTableCell, columnArg: IIdpDataTableColumn): TemplateResult {
|
||||
const content = contentArg === null || contentArg === undefined || contentArg === '' ? '-' : contentArg;
|
||||
return columnArg.mono ? html`<span class="mono-cell">${content}</span>` : html`${content}`;
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
const selectedTab = this.selectedTab || this.tabs[0]?.id || '';
|
||||
return html`
|
||||
<section class="table-card">
|
||||
${this.title || this.badge || this.tabs.length ? html`
|
||||
<div class="table-head">
|
||||
<div class="title-wrap">
|
||||
<div class="title-row">
|
||||
${this.title ? html`<div class="title">${this.title}</div>` : html``}
|
||||
${this.badge ? html`<span class="count-pill">${this.badge}</span>` : html``}
|
||||
</div>
|
||||
${this.subtitle ? html`<div class="subtitle">${this.subtitle}</div>` : html``}
|
||||
</div>
|
||||
${this.tabs.length ? html`
|
||||
<div class="tabs" role="tablist">
|
||||
${this.tabs.map((tabArg) => html`
|
||||
<button
|
||||
class="tab ${tabArg.id === selectedTab ? 'active' : ''}"
|
||||
role="tab"
|
||||
aria-selected=${tabArg.id === selectedTab ? 'true' : 'false'}
|
||||
@click=${() => this.selectTab(tabArg.id)}
|
||||
>${tabArg.label}${tabArg.count !== undefined ? html` (${tabArg.count})` : html``}</button>
|
||||
`)}
|
||||
</div>
|
||||
` : html``}
|
||||
</div>
|
||||
` : html``}
|
||||
${this.rows.length ? html`
|
||||
<div class="table-scroll">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
${this.columns.map((columnArg) => html`
|
||||
<th class=${this.columnClass(columnArg)} style=${columnArg.width ? `width:${columnArg.width}` : ''}>${columnArg.label}</th>
|
||||
`)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${this.rows.map((rowArg) => html`
|
||||
<tr>
|
||||
${this.columns.map((columnArg, indexArg) => html`
|
||||
<td class=${this.columnClass(columnArg)}>${this.renderCell(rowArg.cells[indexArg], columnArg)}</td>
|
||||
`)}
|
||||
</tr>
|
||||
`)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
` : html`
|
||||
<div class="empty-state">
|
||||
<div class="empty-title">${this.emptyTitle}</div>
|
||||
<div class="empty-description">${this.emptyDescription}</div>
|
||||
</div>
|
||||
`}
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
|
||||
import { idpElementStyles } from './tokens.js';
|
||||
import './idp-button.js';
|
||||
import type { TIdpButtonSize, TIdpButtonVariant } from './idp-button.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'idp-form-submit': IdpFormSubmit;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('idp-form-submit')
|
||||
export class IdpFormSubmit extends DeesElement {
|
||||
public static demo = () => html`<idp-form-submit>Continue</idp-form-submit>`;
|
||||
public static demoGroups = ['idp.global v3 primitives'];
|
||||
|
||||
@property({ type: String })
|
||||
public accessor text = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor variant: TIdpButtonVariant = 'accent';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor size: TIdpButtonSize = 'md';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor disabled = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor loading = false;
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
idp-button {
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
private handleClick() {
|
||||
if (this.disabled || this.loading) {
|
||||
return;
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('idp-form-submit-request', {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<idp-button
|
||||
variant=${this.variant}
|
||||
size=${this.size}
|
||||
.disabled=${this.disabled || this.loading}
|
||||
.loading=${this.loading}
|
||||
@click=${this.handleClick}
|
||||
>${this.text || html`<slot></slot>`}</idp-button>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
|
||||
import { idpElementStyles } from './tokens.js';
|
||||
import './idp-input.js';
|
||||
import './idp-checkbox.js';
|
||||
|
||||
export type TIdpFormStatus = 'idle' | 'pending' | 'success' | 'error';
|
||||
export type TIdpFormData = Record<string, string | boolean>;
|
||||
|
||||
export interface IIdpFormSubmitEventDetail {
|
||||
data: TIdpFormData;
|
||||
form: IdpForm;
|
||||
}
|
||||
|
||||
type TFormControl = HTMLElement & {
|
||||
name?: string;
|
||||
key?: string;
|
||||
value?: string;
|
||||
checked?: boolean;
|
||||
validate?: () => boolean;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'idp-form': IdpForm;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('idp-form')
|
||||
export class IdpForm extends DeesElement {
|
||||
public static demo = () => html`
|
||||
<idp-form>
|
||||
<idp-input name="email" label="Email" type="email" required></idp-input>
|
||||
<idp-form-submit>Continue</idp-form-submit>
|
||||
</idp-form>
|
||||
`;
|
||||
public static demoGroups = ['idp.global v3 primitives'];
|
||||
|
||||
@property({ type: String, reflect: true })
|
||||
public accessor status: TIdpFormStatus = 'idle';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor statusMessage = '';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor disabled = false;
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
::slotted(idp-form-submit) {
|
||||
margin-top: 2px;
|
||||
}
|
||||
.status {
|
||||
padding: 11px 13px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--idp-border);
|
||||
background: var(--idp-muted);
|
||||
color: var(--idp-muted-fg);
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
.status.pending {
|
||||
border-color: color-mix(in srgb, var(--idp-accent), transparent 60%);
|
||||
color: var(--idp-accent);
|
||||
}
|
||||
.status.success {
|
||||
border-color: color-mix(in srgb, var(--idp-ok), transparent 60%);
|
||||
color: var(--idp-ok);
|
||||
}
|
||||
.status.error {
|
||||
border-color: color-mix(in srgb, var(--idp-destructive), transparent 60%);
|
||||
color: var(--idp-destructive);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public setStatus(statusArg: TIdpFormStatus, messageArg = '') {
|
||||
this.status = statusArg;
|
||||
this.statusMessage = messageArg;
|
||||
}
|
||||
|
||||
public resetStatus() {
|
||||
this.setStatus('idle', '');
|
||||
}
|
||||
|
||||
public submit() {
|
||||
this.handleSubmit();
|
||||
}
|
||||
|
||||
private getControls() {
|
||||
return Array.from(this.querySelectorAll('idp-input, idp-checkbox')) as TFormControl[];
|
||||
}
|
||||
|
||||
private validateControls() {
|
||||
return this.getControls().every((controlArg) => controlArg.validate ? controlArg.validate() : true);
|
||||
}
|
||||
|
||||
private getFormData(): TIdpFormData {
|
||||
const data: TIdpFormData = {};
|
||||
for (const control of this.getControls()) {
|
||||
const name = control.name || control.key;
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof control.checked === 'boolean') {
|
||||
data[name] = control.checked;
|
||||
} else {
|
||||
data[name] = control.value || '';
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private handleSubmitRequest(eventArg: Event) {
|
||||
eventArg.preventDefault();
|
||||
eventArg.stopPropagation();
|
||||
this.handleSubmit();
|
||||
}
|
||||
|
||||
private handleSubmit(eventArg?: Event) {
|
||||
eventArg?.preventDefault();
|
||||
if (this.disabled || this.status === 'pending') {
|
||||
return;
|
||||
}
|
||||
if (!this.validateControls()) {
|
||||
this.setStatus('error', 'Please check the highlighted fields.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.dispatchEvent(new CustomEvent<IIdpFormSubmitEventDetail>('idp-submit', {
|
||||
detail: {
|
||||
data: this.getFormData(),
|
||||
form: this,
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<form novalidate @submit=${this.handleSubmit} @idp-form-submit-request=${this.handleSubmitRequest}>
|
||||
<slot></slot>
|
||||
${this.statusMessage
|
||||
? html`<div class="status ${this.status}" role="status">${this.statusMessage}</div>`
|
||||
: html``}
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,12 @@ export class IdpInput extends DeesElement {
|
||||
@property({ type: String })
|
||||
public accessor label = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor name = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor key = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor hint = '';
|
||||
|
||||
@@ -27,6 +33,15 @@ export class IdpInput extends DeesElement {
|
||||
@property({ type: String })
|
||||
public accessor type = 'text';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor autocomplete = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor error = '';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor required = false;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor disabled = false;
|
||||
|
||||
@@ -66,18 +81,49 @@ export class IdpInput extends DeesElement {
|
||||
input:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.hint {
|
||||
input[aria-invalid='true'] {
|
||||
border-color: var(--idp-destructive);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--idp-destructive), transparent 86%);
|
||||
}
|
||||
.hint,
|
||||
.error {
|
||||
color: var(--idp-muted-fg);
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.error {
|
||||
color: var(--idp-destructive);
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public focus() {
|
||||
this.shadowRoot?.querySelector('input')?.focus();
|
||||
}
|
||||
|
||||
public validate() {
|
||||
const input = this.shadowRoot?.querySelector('input');
|
||||
if (this.required && !this.value.trim()) {
|
||||
this.error = `${this.label || this.name || 'This field'} is required.`;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input && !input.checkValidity()) {
|
||||
this.error = input.validationMessage;
|
||||
return false;
|
||||
}
|
||||
|
||||
this.error = '';
|
||||
return true;
|
||||
}
|
||||
|
||||
private handleInput(eventArg: Event) {
|
||||
this.value = (eventArg.target as HTMLInputElement).value;
|
||||
if (this.error) {
|
||||
this.validate();
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('idp-input-change', {
|
||||
detail: { value: this.value },
|
||||
detail: { name: this.name || this.key, key: this.key || this.name, value: this.value },
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
@@ -89,12 +135,16 @@ export class IdpInput extends DeesElement {
|
||||
${this.label ? html`<span class="label">${this.label}</span>` : html``}
|
||||
<input
|
||||
.value=${this.value}
|
||||
name=${this.name || this.key}
|
||||
type=${this.type}
|
||||
placeholder=${this.placeholder}
|
||||
autocomplete=${this.autocomplete}
|
||||
?required=${this.required}
|
||||
?disabled=${this.disabled}
|
||||
aria-invalid=${this.error ? 'true' : 'false'}
|
||||
@input=${this.handleInput}
|
||||
/>
|
||||
${this.hint ? html`<span class="hint">${this.hint}</span>` : html``}
|
||||
${this.error ? html`<span class="error">${this.error}</span>` : this.hint ? html`<span class="hint">${this.hint}</span>` : html``}
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ export class IdpLandingHero extends DeesElement {
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: #0a0a0a;
|
||||
color: #fafafa;
|
||||
border-bottom: 1px solid #1c1c1c;
|
||||
background: var(--idp-bg);
|
||||
color: var(--idp-fg);
|
||||
border-bottom: 1px solid var(--idp-border-soft);
|
||||
}
|
||||
.grid {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: linear-gradient(to right, rgba(255,255,255,0.025) 1px, transparent 1px), linear-gradient(to bottom, rgba(255,255,255,0.025) 1px, transparent 1px);
|
||||
background-image: linear-gradient(to right, color-mix(in srgb, var(--idp-fg), transparent 97%) 1px, transparent 1px), linear-gradient(to bottom, color-mix(in srgb, var(--idp-fg), transparent 97%) 1px, transparent 1px);
|
||||
background-size: 56px 56px;
|
||||
mask-image: radial-gradient(ellipse 80% 60% at 50% 0%, #000 30%, transparent 70%);
|
||||
pointer-events: none;
|
||||
@@ -60,17 +60,17 @@ export class IdpLandingHero extends DeesElement {
|
||||
gap: 7px;
|
||||
margin-bottom: 28px;
|
||||
padding: 5px 12px 5px 8px;
|
||||
border: 1px solid #262626;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 999px;
|
||||
background: rgba(255,255,255,0.04);
|
||||
color: hsl(0 0% 70%);
|
||||
background: var(--idp-muted);
|
||||
color: var(--idp-fg-3);
|
||||
font-size: 12px;
|
||||
}
|
||||
.pill {
|
||||
padding: 2px 7px;
|
||||
border-radius: 999px;
|
||||
background: rgba(59,130,246,0.18);
|
||||
color: #60a5fa;
|
||||
color: var(--idp-accent-hover);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
@@ -85,7 +85,7 @@ export class IdpLandingHero extends DeesElement {
|
||||
line-height: 0.96;
|
||||
}
|
||||
h1 em {
|
||||
color: #60a5fa;
|
||||
color: var(--idp-accent-hover);
|
||||
font-family: var(--idp-serif);
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
@@ -93,7 +93,7 @@ export class IdpLandingHero extends DeesElement {
|
||||
.sub {
|
||||
max-width: 660px;
|
||||
margin: 0 auto 36px;
|
||||
color: hsl(0 0% 70%);
|
||||
color: var(--idp-fg-3);
|
||||
font-size: clamp(16px, 1.6vw, 19px);
|
||||
line-height: 1.55;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ export class IdpLandingHero extends DeesElement {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.fineprint {
|
||||
color: hsl(0 0% 28%);
|
||||
color: var(--idp-muted-fg);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.04em;
|
||||
@@ -156,7 +156,7 @@ export class IdpLandingHero extends DeesElement {
|
||||
<div class="fineprint"><span>MIT licensed</span><span>Self-hostable</span><span>No credit card</span><span>Cardano mainnet</span></div>
|
||||
<div class="product">
|
||||
<div class="product-glow"></div>
|
||||
<idp-dashboard-window dark></idp-dashboard-window>
|
||||
<idp-dashboard-window></idp-dashboard-window>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -21,19 +21,6 @@ export class IdpLandingPage extends DeesElement {
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
--idp-bg: #0a0a0a;
|
||||
--idp-bg-2: #111111;
|
||||
--idp-card: #121212;
|
||||
--idp-card-2: #161616;
|
||||
--idp-fg: #fafafa;
|
||||
--idp-fg-2: #d4d4d8;
|
||||
--idp-fg-3: hsl(0 0% 70%);
|
||||
--idp-muted-fg: hsl(0 0% 55%);
|
||||
--idp-border: #262626;
|
||||
--idp-border-soft: #1c1c1c;
|
||||
--idp-border-strong: #333333;
|
||||
--idp-accent: #3b82f6;
|
||||
--idp-accent-hover: #60a5fa;
|
||||
background: var(--idp-bg);
|
||||
color: var(--idp-fg);
|
||||
}
|
||||
@@ -54,7 +41,7 @@ export class IdpLandingPage extends DeesElement {
|
||||
margin: 0 auto;
|
||||
padding: 0 32px;
|
||||
border-bottom: 1px solid var(--idp-border-soft);
|
||||
background: rgba(10,10,10,0.86);
|
||||
background: color-mix(in srgb, var(--idp-bg), transparent 14%);
|
||||
backdrop-filter: blur(14px) saturate(140%);
|
||||
}
|
||||
.nav-shell {
|
||||
@@ -62,7 +49,7 @@ export class IdpLandingPage extends DeesElement {
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
border-bottom: 1px solid var(--idp-border-soft);
|
||||
background: rgba(10,10,10,0.86);
|
||||
background: color-mix(in srgb, var(--idp-bg), transparent 14%);
|
||||
}
|
||||
.logo {
|
||||
display: inline-flex;
|
||||
@@ -93,7 +80,7 @@ export class IdpLandingPage extends DeesElement {
|
||||
text-decoration: none;
|
||||
}
|
||||
.links a:hover {
|
||||
background: rgba(255,255,255,0.04);
|
||||
background: var(--idp-muted);
|
||||
color: var(--idp-fg);
|
||||
}
|
||||
.status {
|
||||
@@ -288,7 +275,7 @@ export class IdpLandingPage extends DeesElement {
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
background: linear-gradient(140deg, #1a1a1a 0%, #0a0a0a 100%);
|
||||
background: linear-gradient(140deg, var(--idp-card) 0%, var(--idp-bg) 100%);
|
||||
}
|
||||
.identity-card::after {
|
||||
content: '';
|
||||
@@ -416,7 +403,7 @@ export class IdpLandingPage extends DeesElement {
|
||||
}
|
||||
.chain-block.idp {
|
||||
border-left: 2px solid var(--idp-accent);
|
||||
background: rgba(0,80,185,0.08);
|
||||
background: var(--idp-accent-soft);
|
||||
}
|
||||
.tiers {
|
||||
display: grid;
|
||||
@@ -431,7 +418,7 @@ export class IdpLandingPage extends DeesElement {
|
||||
}
|
||||
.tier.featured {
|
||||
border-color: var(--idp-accent);
|
||||
background: linear-gradient(180deg, rgba(59,130,246,0.06) 0%, var(--idp-bg-2) 40%);
|
||||
background: linear-gradient(180deg, var(--idp-accent-soft) 0%, var(--idp-bg-2) 40%);
|
||||
}
|
||||
.tier-name {
|
||||
margin-bottom: 10px;
|
||||
|
||||
@@ -25,8 +25,8 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
.showcase {
|
||||
min-height: 100vh;
|
||||
padding: 56px;
|
||||
background: radial-gradient(circle at 1px 1px, rgba(0,0,0,0.08) 1px, transparent 0) 0 0 / 24px 24px, #fafafa;
|
||||
color: #09090b;
|
||||
background: radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--idp-fg), transparent 92%) 1px, transparent 0) 0 0 / 24px 24px, var(--idp-bg);
|
||||
color: var(--idp-fg);
|
||||
}
|
||||
.head {
|
||||
max-width: 1180px;
|
||||
@@ -38,10 +38,10 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
gap: 6px;
|
||||
margin-bottom: 16px;
|
||||
padding: 4px 10px;
|
||||
border: 1px solid #e4e4e7;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: #52525b;
|
||||
background: var(--idp-card);
|
||||
color: var(--idp-fg-3);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #16a34a;
|
||||
background: var(--idp-ok);
|
||||
}
|
||||
h1 {
|
||||
max-width: 900px;
|
||||
@@ -63,7 +63,7 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
p {
|
||||
max-width: 680px;
|
||||
margin: 0;
|
||||
color: #52525b;
|
||||
color: var(--idp-fg-3);
|
||||
font-size: 16px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
@@ -73,13 +73,13 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
gap: 24px;
|
||||
margin-top: 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #e4e4e7;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
background: var(--idp-card);
|
||||
}
|
||||
.token-label {
|
||||
margin-bottom: 4px;
|
||||
color: #71717a;
|
||||
color: var(--idp-muted-fg);
|
||||
font-size: 10px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
@@ -89,7 +89,7 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
color: #18181b;
|
||||
color: var(--idp-fg);
|
||||
font-size: 13px;
|
||||
font-weight: 550;
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
height: 18px;
|
||||
border-radius: 5px;
|
||||
background: var(--swatch);
|
||||
border: 1px solid #e4e4e7;
|
||||
border: 1px solid var(--idp-border);
|
||||
}
|
||||
.section {
|
||||
max-width: 1180px;
|
||||
@@ -106,7 +106,7 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
}
|
||||
.section-title {
|
||||
margin-bottom: 18px;
|
||||
color: #71717a;
|
||||
color: var(--idp-muted-fg);
|
||||
font-family: var(--idp-mono);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
@@ -126,9 +126,9 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
align-items: start;
|
||||
}
|
||||
.watch, .ipad, .mac {
|
||||
border: 1px solid #e4e4e7;
|
||||
background: #fff;
|
||||
box-shadow: 0 20px 50px rgba(0,0,0,0.08);
|
||||
border: 1px solid var(--idp-border);
|
||||
background: var(--idp-card);
|
||||
box-shadow: 0 20px 50px color-mix(in srgb, var(--idp-fg), transparent 92%);
|
||||
}
|
||||
.watch {
|
||||
width: 236px;
|
||||
@@ -188,8 +188,8 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
}
|
||||
.ipad-sidebar {
|
||||
padding: 18px;
|
||||
border-right: 1px solid #e4e4e7;
|
||||
background: #f8f8f7;
|
||||
border-right: 1px solid var(--idp-border);
|
||||
background: var(--idp-card-2);
|
||||
}
|
||||
.ipad-main {
|
||||
padding: 22px;
|
||||
@@ -200,8 +200,9 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
gap: 10px;
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
border: 1px solid #e4e4e7;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 12px;
|
||||
background: var(--idp-card);
|
||||
}
|
||||
.mac {
|
||||
overflow: hidden;
|
||||
@@ -211,7 +212,7 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
padding: 11px 14px;
|
||||
border-bottom: 1px solid #e4e4e7;
|
||||
border-bottom: 1px solid var(--idp-border);
|
||||
}
|
||||
.tdot {
|
||||
width: 10px;
|
||||
@@ -229,8 +230,15 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
border: 1px solid #e4e4e7;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 10px;
|
||||
background: var(--idp-card);
|
||||
}
|
||||
.inline-muted {
|
||||
color: var(--idp-muted-fg);
|
||||
}
|
||||
.watch-muted {
|
||||
color: #a1a1aa;
|
||||
}
|
||||
.row-label {
|
||||
display: inline-flex;
|
||||
@@ -276,8 +284,8 @@ export class IdpMobileShowcase extends DeesElement {
|
||||
<section class="section">
|
||||
<div class="section-title">Watch, iPad, Mac</div>
|
||||
<div class="multi">
|
||||
<div class="watch"><div class="watch-screen"><div class="watch-app">idp.global</div><idp-icon name="shield" size="28" style="margin:0 auto;color:#60a5fa"></idp-icon><div class="watch-title">GitHub wants access</div><div style="color:#a1a1aa;font-size:12px;">repo:read - Berlin</div><div class="watch-actions"><button><idp-icon name="x" size="13"></idp-icon>Deny</button><button class="approve"><idp-icon name="check" size="13"></idp-icon>Approve</button></div></div></div>
|
||||
<div class="ipad"><div class="ipad-shell"><aside class="ipad-sidebar"><strong>Inbox</strong><p>3 pending approvals</p><div class="ipad-card"><idp-icon name="globe" size="16"></idp-icon><div><strong>GitHub OAuth</strong><br/><span style="color:#71717a">repo:read - now</span></div></div><div class="ipad-card"><idp-icon name="cloud" size="16"></idp-icon><div><strong>Hetzner Cloud</strong><br/><span style="color:#71717a">new network - 8m</span></div></div></aside><main class="ipad-main"><h2>Approval detail</h2><p>Full context before a sensitive action is approved.</p><div class="ipad-card"><idp-icon name="laptop" size="16"></idp-icon><div><strong>Device</strong><br/>MacBook Pro - Safari - Berlin, DE</div></div><div class="ipad-card"><idp-icon name="key" size="16"></idp-icon><div><strong>Requested scopes</strong><br/>openid, profile, email, repo:read</div></div></main></div></div>
|
||||
<div class="watch"><div class="watch-screen"><div class="watch-app">idp.global</div><idp-icon name="shield" size="28" style="margin:0 auto;color:var(--idp-accent-hover)"></idp-icon><div class="watch-title">GitHub wants access</div><div class="watch-muted" style="font-size:12px;">repo:read - Berlin</div><div class="watch-actions"><button><idp-icon name="x" size="13"></idp-icon>Deny</button><button class="approve"><idp-icon name="check" size="13"></idp-icon>Approve</button></div></div></div>
|
||||
<div class="ipad"><div class="ipad-shell"><aside class="ipad-sidebar"><strong>Inbox</strong><p>3 pending approvals</p><div class="ipad-card"><idp-icon name="globe" size="16"></idp-icon><div><strong>GitHub OAuth</strong><br/><span class="inline-muted">repo:read - now</span></div></div><div class="ipad-card"><idp-icon name="cloud" size="16"></idp-icon><div><strong>Hetzner Cloud</strong><br/><span class="inline-muted">new network - 8m</span></div></div></aside><main class="ipad-main"><h2>Approval detail</h2><p>Full context before a sensitive action is approved.</p><div class="ipad-card"><idp-icon name="laptop" size="16"></idp-icon><div><strong>Device</strong><br/>MacBook Pro - Safari - Berlin, DE</div></div><div class="ipad-card"><idp-icon name="key" size="16"></idp-icon><div><strong>Requested scopes</strong><br/>openid, profile, email, repo:read</div></div></main></div></div>
|
||||
<div class="mac"><div class="mac-bar"><span class="tdot" style="background:#ff5f57"></span><span class="tdot" style="background:#ffbd2e"></span><span class="tdot" style="background:#28c840"></span></div><div class="mac-body"><strong>Menu bar approvals</strong><div class="mac-row"><span class="row-label"><idp-icon name="globe" size="15"></idp-icon>GitHub OAuth</span><idp-button variant="accent" size="sm" icon="check">Approve</idp-button></div><div class="mac-row"><span class="row-label"><idp-icon name="nfc" size="15"></idp-icon>NFC tap - door 4F</span><idp-button variant="ghost" size="sm" icon="chevron-right">Review</idp-button></div><div class="mac-row"><span class="row-label"><idp-icon name="key" size="15"></idp-icon>Key rotation</span><idp-button variant="ghost" size="sm" icon="shield">Confirm</idp-button></div></div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import { DeesElement, html, property, customElement, css, type TemplateResult } from '@design.estate/dees-element';
|
||||
import { idpElementStyles } from './tokens.js';
|
||||
|
||||
export interface IIdpSelectOption {
|
||||
option: string;
|
||||
key: string;
|
||||
payload?: string;
|
||||
}
|
||||
|
||||
export interface IIdpSelectEventDetail {
|
||||
key: string;
|
||||
payload?: string;
|
||||
selectedOption: IIdpSelectOption | null;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'idp-select': IdpSelect;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('idp-select')
|
||||
export class IdpSelect extends DeesElement {
|
||||
public static demo = () => html`
|
||||
<idp-select
|
||||
label="Organization"
|
||||
.options=${[
|
||||
{ option: 'Lossless GmbH', key: 'lossless', payload: 'lossless' },
|
||||
{ option: '+ Create new...', key: '__create_new__', payload: '__create_new__' },
|
||||
]}
|
||||
></idp-select>
|
||||
`;
|
||||
public static demoGroups = ['idp.global v3 primitives'];
|
||||
|
||||
@property({ type: String })
|
||||
public accessor label = '';
|
||||
|
||||
@property({ type: String })
|
||||
public accessor placeholder = 'Select...';
|
||||
|
||||
@property({ type: Array })
|
||||
public accessor options: IIdpSelectOption[] = [];
|
||||
|
||||
@property({ type: Object })
|
||||
public accessor selectedOption: IIdpSelectOption | null = null;
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public accessor disabled = false;
|
||||
|
||||
public static styles = [
|
||||
...idpElementStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
label {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
.label {
|
||||
color: var(--idp-fg);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
select {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 34px 0 10px;
|
||||
border: 1px solid var(--idp-border);
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
background: var(--idp-card);
|
||||
color: var(--idp-fg);
|
||||
font-family: var(--idp-font);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: border-color 120ms ease, box-shadow 120ms ease;
|
||||
}
|
||||
select:focus {
|
||||
border-color: var(--idp-accent);
|
||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--idp-accent), transparent 86%);
|
||||
}
|
||||
select:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
private handleChange(eventArg: Event) {
|
||||
const key = (eventArg.target as HTMLSelectElement).value;
|
||||
const selectedOption = this.options.find((optionArg) => optionArg.key === key) || null;
|
||||
this.selectedOption = selectedOption;
|
||||
this.dispatchEvent(new CustomEvent<IIdpSelectEventDetail>('idp-select', {
|
||||
detail: {
|
||||
key,
|
||||
payload: selectedOption?.payload,
|
||||
selectedOption,
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
}));
|
||||
}
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<label>
|
||||
${this.label ? html`<span class="label">${this.label}</span>` : html``}
|
||||
<select .value=${this.selectedOption?.key || ''} ?disabled=${this.disabled} @change=${this.handleChange}>
|
||||
<option value="" disabled>${this.placeholder}</option>
|
||||
${this.options.map((optionArg) => html`
|
||||
<option value=${optionArg.key}>${optionArg.option}</option>
|
||||
`)}
|
||||
</select>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,11 @@ export * from './idp-button.js';
|
||||
export * from './idp-badge.js';
|
||||
export * from './idp-card.js';
|
||||
export * from './idp-input.js';
|
||||
export * from './idp-checkbox.js';
|
||||
export * from './idp-form.js';
|
||||
export * from './idp-form-submit.js';
|
||||
export * from './idp-select.js';
|
||||
export * from './idp-data-table.js';
|
||||
export * from './idp-toggle.js';
|
||||
export * from './idp-approval-card.js';
|
||||
export * from './idp-mobile-frame.js';
|
||||
|
||||
+157
-84
@@ -11,11 +11,11 @@ export const idpTheme = {
|
||||
card: 'var(--idp-card)',
|
||||
primary: 'var(--idp-primary)',
|
||||
primaryFg: 'var(--idp-primary-fg)',
|
||||
accent: 'var(--idp-accent)',
|
||||
accentHover: 'var(--idp-accent-hover)',
|
||||
accentSoft: 'var(--idp-accent-soft)',
|
||||
info: 'var(--idp-info)',
|
||||
destructive: 'var(--idp-destructive)',
|
||||
accent: 'var(--idp-accent)',
|
||||
accentHover: 'var(--idp-accent-hover)',
|
||||
accentSoft: 'var(--idp-accent-soft)',
|
||||
info: 'var(--idp-info)',
|
||||
destructive: 'var(--idp-destructive)',
|
||||
ok: 'var(--idp-ok)',
|
||||
warn: 'var(--idp-warn)',
|
||||
radius: 'var(--idp-radius)',
|
||||
@@ -23,47 +23,104 @@ export const idpTheme = {
|
||||
|
||||
export const idpBaseStyles = css`
|
||||
:host {
|
||||
--idp-bg: #fafaf9;
|
||||
--idp-bg-2: #f4f4f2;
|
||||
--idp-fg: #0a0a0a;
|
||||
--idp-fg-2: #3f3f46;
|
||||
--idp-fg-3: #52525b;
|
||||
--idp-muted: #f1f1ef;
|
||||
--idp-muted-fg: #71717a;
|
||||
--idp-border: #e4e4e7;
|
||||
--idp-border-soft: #ededec;
|
||||
--idp-border-strong: #d4d4d8;
|
||||
--idp-card: #ffffff;
|
||||
--idp-card-2: #f8f8f7;
|
||||
--idp-primary: #18181b;
|
||||
--idp-primary-fg: #fafafa;
|
||||
--idp-accent: #0050b9;
|
||||
--idp-accent-hover: #0069f2;
|
||||
--idp-accent-fg: #ffffff;
|
||||
--idp-accent-soft: #e6effb;
|
||||
--idp-destructive: #ef4444;
|
||||
--idp-ok: #16a34a;
|
||||
--idp-ok-bg: #f0fdf4;
|
||||
--idp-ok-border: #bbf7d0;
|
||||
--idp-warn: #b45309;
|
||||
--idp-warn-bg: #fef9c3;
|
||||
--idp-warn-border: #fde68a;
|
||||
--idp-error: #dc2626;
|
||||
--idp-error-bg: #fef2f2;
|
||||
--idp-error-border: #fecaca;
|
||||
--idp-info: #1e40af;
|
||||
--idp-info-bg: #eff6ff;
|
||||
--idp-info-border: #bfdbfe;
|
||||
--idp-chart-1: #0050b9;
|
||||
--idp-chart-2: #16a34a;
|
||||
--idp-chart-3: #dc2626;
|
||||
--idp-chart-4: #b45309;
|
||||
--idp-chart-5: #6e5be6;
|
||||
--idp-spark-up: #16a34a;
|
||||
--idp-spark-down: #dc2626;
|
||||
--idp-spark-info: #0050b9;
|
||||
--idp-radius: 8px;
|
||||
--idp-radius-lg: 12px;
|
||||
--sh-bg: ${cssManager.bdTheme('#FAFAF9', '#0A0A0A')};
|
||||
--sh-bg-2: ${cssManager.bdTheme('#F4F4F2', '#111111')};
|
||||
--sh-card: ${cssManager.bdTheme('#FFFFFF', '#121212')};
|
||||
--sh-card-2: ${cssManager.bdTheme('#F8F8F7', '#161616')};
|
||||
--sh-muted: ${cssManager.bdTheme('#F1F1EF', '#161616')};
|
||||
--sh-muted-fg: ${cssManager.bdTheme('#71717A', 'hsl(0 0% 55%)')};
|
||||
--sh-fg: ${cssManager.bdTheme('#0A0A0A', '#FAFAFA')};
|
||||
--sh-fg-2: ${cssManager.bdTheme('#3F3F46', '#D4D4D8')};
|
||||
--sh-fg-3: ${cssManager.bdTheme('#52525B', 'hsl(0 0% 70%)')};
|
||||
--sh-fg-4: ${cssManager.bdTheme('#A1A1AA', 'hsl(0 0% 35%)')};
|
||||
--sh-border: ${cssManager.bdTheme('#E4E4E7', '#262626')};
|
||||
--sh-border-soft: ${cssManager.bdTheme('#EDEDEC', '#1C1C1C')};
|
||||
--sh-border-strong: ${cssManager.bdTheme('#D4D4D8', '#333333')};
|
||||
--sh-input: ${cssManager.bdTheme('#FFFFFF', '#161616')};
|
||||
--sh-input-bg: ${cssManager.bdTheme('#FFFFFF', '#0A0A0A')};
|
||||
--sh-hover: ${cssManager.bdTheme('rgba(0,0,0,0.04)', 'rgba(255,255,255,0.04)')};
|
||||
--sh-primary: ${cssManager.bdTheme('#18181B', '#FAFAFA')};
|
||||
--sh-primary-fg: ${cssManager.bdTheme('#FAFAFA', '#18181B')};
|
||||
--sh-accent: ${cssManager.bdTheme('#0050B9', '#3B82F6')};
|
||||
--sh-accent-h: ${cssManager.bdTheme('#0069F2', '#60A5FA')};
|
||||
--sh-accent-fg: #FFFFFF;
|
||||
--sh-accent-soft: ${cssManager.bdTheme('#E6EFFB', 'rgba(59,130,246,0.15)')};
|
||||
--sh-accent-soft-fg: ${cssManager.bdTheme('#0050B9', '#93BBFD')};
|
||||
--sh-accent-ring: ${cssManager.bdTheme('rgba(0,80,185,0.2)', 'rgba(59,130,246,0.35)')};
|
||||
--sh-ok: ${cssManager.bdTheme('#16A34A', '#4ADE80')};
|
||||
--sh-ok-bg: ${cssManager.bdTheme('#F0FDF4', 'rgba(20,83,45,0.4)')};
|
||||
--sh-ok-border: ${cssManager.bdTheme('#BBF7D0', 'rgba(74,222,128,0.25)')};
|
||||
--sh-warn: ${cssManager.bdTheme('#B45309', '#FBBF24')};
|
||||
--sh-warn-bg: ${cssManager.bdTheme('#FEF9C3', 'rgba(69,26,3,0.6)')};
|
||||
--sh-warn-border: ${cssManager.bdTheme('#FDE68A', 'rgba(251,191,36,0.25)')};
|
||||
--sh-err: ${cssManager.bdTheme('#DC2626', '#F87171')};
|
||||
--sh-err-bg: ${cssManager.bdTheme('#FEF2F2', 'rgba(69,10,10,0.6)')};
|
||||
--sh-err-border: ${cssManager.bdTheme('#FECACA', 'rgba(248,113,113,0.25)')};
|
||||
--sh-info: ${cssManager.bdTheme('#1E40AF', '#93BBFD')};
|
||||
--sh-info-bg: ${cssManager.bdTheme('#EFF6FF', 'rgba(59,130,246,0.15)')};
|
||||
--sh-info-border: ${cssManager.bdTheme('#BFDBFE', 'rgba(59,130,246,0.3)')};
|
||||
--sh-destructive: #EF4444;
|
||||
--sh-ring: ${cssManager.bdTheme('#A1A1AA', '#3B82F6')};
|
||||
--sh-radius: 8px;
|
||||
--sh-radius-lg: 12px;
|
||||
--sh-chart-1: ${cssManager.bdTheme('#0050B9', '#3B82F6')};
|
||||
--sh-chart-2: ${cssManager.bdTheme('#16A34A', '#4ADE80')};
|
||||
--sh-chart-3: ${cssManager.bdTheme('#DC2626', '#F87171')};
|
||||
--sh-chart-4: ${cssManager.bdTheme('#B45309', '#FBBF24')};
|
||||
--sh-chart-5: ${cssManager.bdTheme('#6E5BE6', '#A78BFA')};
|
||||
--sh-grid: ${cssManager.bdTheme('#E4E4E7', '#262626')};
|
||||
--sh-grid-soft: ${cssManager.bdTheme('rgba(0,0,0,0.04)', 'rgba(255,255,255,0.04)')};
|
||||
--sh-spark-up: ${cssManager.bdTheme('#16A34A', '#4ADE80')};
|
||||
--sh-spark-down: ${cssManager.bdTheme('#DC2626', '#F87171')};
|
||||
--sh-spark-info: ${cssManager.bdTheme('#0050B9', '#93BBFD')};
|
||||
--sh-d1: ${cssManager.bdTheme('#0050B9', '#93BBFD')};
|
||||
--sh-d2: ${cssManager.bdTheme('#16A34A', '#4ADE80')};
|
||||
--sh-d3: ${cssManager.bdTheme('#B45309', '#FBBF24')};
|
||||
--sh-d4: ${cssManager.bdTheme('#DC2626', '#F87171')};
|
||||
--sh-d5: ${cssManager.bdTheme('#6E5BE6', '#A78BFA')};
|
||||
--sh-d6: ${cssManager.bdTheme('#0891B2', '#22D3EE')};
|
||||
|
||||
--idp-bg: var(--sh-bg);
|
||||
--idp-bg-2: var(--sh-bg-2);
|
||||
--idp-fg: var(--sh-fg);
|
||||
--idp-fg-2: var(--sh-fg-2);
|
||||
--idp-fg-3: var(--sh-fg-3);
|
||||
--idp-muted: var(--sh-muted);
|
||||
--idp-muted-fg: var(--sh-muted-fg);
|
||||
--idp-border: var(--sh-border);
|
||||
--idp-border-soft: var(--sh-border-soft);
|
||||
--idp-border-strong: var(--sh-border-strong);
|
||||
--idp-card: var(--sh-card);
|
||||
--idp-card-2: var(--sh-card-2);
|
||||
--idp-primary: var(--sh-primary);
|
||||
--idp-primary-fg: var(--sh-primary-fg);
|
||||
--idp-accent: var(--sh-accent);
|
||||
--idp-accent-hover: var(--sh-accent-h);
|
||||
--idp-accent-fg: var(--sh-accent-fg);
|
||||
--idp-accent-soft: var(--sh-accent-soft);
|
||||
--idp-destructive: var(--sh-destructive);
|
||||
--idp-ok: var(--sh-ok);
|
||||
--idp-ok-bg: var(--sh-ok-bg);
|
||||
--idp-ok-border: var(--sh-ok-border);
|
||||
--idp-warn: var(--sh-warn);
|
||||
--idp-warn-bg: var(--sh-warn-bg);
|
||||
--idp-warn-border: var(--sh-warn-border);
|
||||
--idp-error: var(--sh-err);
|
||||
--idp-error-bg: var(--sh-err-bg);
|
||||
--idp-error-border: var(--sh-err-border);
|
||||
--idp-info: var(--sh-info);
|
||||
--idp-info-bg: var(--sh-info-bg);
|
||||
--idp-info-border: var(--sh-info-border);
|
||||
--idp-chart-1: var(--sh-chart-1);
|
||||
--idp-chart-2: var(--sh-chart-2);
|
||||
--idp-chart-3: var(--sh-chart-3);
|
||||
--idp-chart-4: var(--sh-chart-4);
|
||||
--idp-chart-5: var(--sh-chart-5);
|
||||
--idp-spark-up: var(--sh-spark-up);
|
||||
--idp-spark-down: var(--sh-spark-down);
|
||||
--idp-spark-info: var(--sh-spark-info);
|
||||
--idp-radius: var(--sh-radius);
|
||||
--idp-radius-lg: var(--sh-radius-lg);
|
||||
--idp-font: 'Geist', ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
--idp-display: 'Plus Jakarta Sans', 'Geist', ui-sans-serif, system-ui, sans-serif;
|
||||
--idp-mono: 'Intel One Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
||||
@@ -76,44 +133,60 @@ export const idpBaseStyles = css`
|
||||
|
||||
:host([theme="dark"]),
|
||||
:host([dark]) {
|
||||
--idp-bg: #0a0a0a;
|
||||
--idp-bg-2: #111111;
|
||||
--idp-fg: #fafafa;
|
||||
--idp-fg-2: #d4d4d8;
|
||||
--idp-fg-3: hsl(0 0% 70%);
|
||||
--idp-muted: #161616;
|
||||
--idp-muted-fg: hsl(0 0% 55%);
|
||||
--idp-border: #262626;
|
||||
--idp-border-soft: #1c1c1c;
|
||||
--idp-border-strong: #333333;
|
||||
--idp-card: #121212;
|
||||
--idp-card-2: #161616;
|
||||
--idp-primary: #fafafa;
|
||||
--idp-primary-fg: #18181b;
|
||||
--idp-accent: #3b82f6;
|
||||
--idp-accent-hover: #60a5fa;
|
||||
--idp-accent-soft: rgba(59, 130, 246, 0.15);
|
||||
--idp-destructive: #ef4444;
|
||||
--idp-ok: #4ade80;
|
||||
--idp-ok-bg: rgba(20, 83, 45, 0.4);
|
||||
--idp-ok-border: rgba(74, 222, 128, 0.25);
|
||||
--idp-warn: #fbbf24;
|
||||
--idp-warn-bg: rgba(69, 26, 3, 0.6);
|
||||
--idp-warn-border: rgba(251, 191, 36, 0.25);
|
||||
--idp-error: #f87171;
|
||||
--idp-error-bg: rgba(69, 10, 10, 0.6);
|
||||
--idp-error-border: rgba(248, 113, 113, 0.25);
|
||||
--idp-info: #93bbfd;
|
||||
--idp-info-bg: rgba(59, 130, 246, 0.15);
|
||||
--idp-info-border: rgba(59, 130, 246, 0.3);
|
||||
--idp-chart-1: #3b82f6;
|
||||
--idp-chart-2: #4ade80;
|
||||
--idp-chart-3: #f87171;
|
||||
--idp-chart-4: #fbbf24;
|
||||
--idp-chart-5: #a78bfa;
|
||||
--idp-spark-up: #4ade80;
|
||||
--idp-spark-down: #f87171;
|
||||
--idp-spark-info: #93bbfd;
|
||||
--sh-bg: #0A0A0A;
|
||||
--sh-bg-2: #111111;
|
||||
--sh-card: #121212;
|
||||
--sh-card-2: #161616;
|
||||
--sh-muted: #161616;
|
||||
--sh-muted-fg: hsl(0 0% 55%);
|
||||
--sh-fg: #FAFAFA;
|
||||
--sh-fg-2: #D4D4D8;
|
||||
--sh-fg-3: hsl(0 0% 70%);
|
||||
--sh-fg-4: hsl(0 0% 35%);
|
||||
--sh-border: #262626;
|
||||
--sh-border-soft: #1C1C1C;
|
||||
--sh-border-strong: #333333;
|
||||
--sh-input: #161616;
|
||||
--sh-input-bg: #0A0A0A;
|
||||
--sh-hover: rgba(255,255,255,0.04);
|
||||
--sh-primary: #FAFAFA;
|
||||
--sh-primary-fg: #18181B;
|
||||
--sh-accent: #3B82F6;
|
||||
--sh-accent-h: #60A5FA;
|
||||
--sh-accent-fg: #FFFFFF;
|
||||
--sh-accent-soft: rgba(59,130,246,0.15);
|
||||
--sh-accent-soft-fg: #93BBFD;
|
||||
--sh-accent-ring: rgba(59,130,246,0.35);
|
||||
--sh-ok: #4ADE80;
|
||||
--sh-ok-bg: rgba(20,83,45,0.4);
|
||||
--sh-ok-border: rgba(74,222,128,0.25);
|
||||
--sh-warn: #FBBF24;
|
||||
--sh-warn-bg: rgba(69,26,3,0.6);
|
||||
--sh-warn-border: rgba(251,191,36,0.25);
|
||||
--sh-err: #F87171;
|
||||
--sh-err-bg: rgba(69,10,10,0.6);
|
||||
--sh-err-border: rgba(248,113,113,0.25);
|
||||
--sh-info: #93BBFD;
|
||||
--sh-info-bg: rgba(59,130,246,0.15);
|
||||
--sh-info-border: rgba(59,130,246,0.3);
|
||||
--sh-destructive: #EF4444;
|
||||
--sh-ring: #3B82F6;
|
||||
--sh-chart-1: #3B82F6;
|
||||
--sh-chart-2: #4ADE80;
|
||||
--sh-chart-3: #F87171;
|
||||
--sh-chart-4: #FBBF24;
|
||||
--sh-chart-5: #A78BFA;
|
||||
--sh-grid: #262626;
|
||||
--sh-grid-soft: rgba(255,255,255,0.04);
|
||||
--sh-spark-up: #4ADE80;
|
||||
--sh-spark-down: #F87171;
|
||||
--sh-spark-info: #93BBFD;
|
||||
--sh-d1: #93BBFD;
|
||||
--sh-d2: #4ADE80;
|
||||
--sh-d3: #FBBF24;
|
||||
--sh-d4: #F87171;
|
||||
--sh-d5: #A78BFA;
|
||||
--sh-d6: #22D3EE;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user