From 5a561690be47815f40fb7a3883cbcf5c7c5e77ab Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 07:04:25 +0000 Subject: [PATCH] feat(ui): polish scm agent views Co-Authored-By: Virgil --- pkg/api/ui/dist/core-scm.js | 1812 +++++++++++++++++++++++------------ ui/index.html | 36 +- ui/src/scm-installed.ts | 235 ++++- ui/src/scm-manifest.ts | 235 ++++- ui/src/scm-marketplace.ts | 398 ++++++-- ui/src/scm-panel.ts | 138 ++- ui/src/scm-registry.ts | 178 +++- 7 files changed, 2127 insertions(+), 905 deletions(-) diff --git a/pkg/api/ui/dist/core-scm.js b/pkg/api/ui/dist/core-scm.js index df348a3..4c1d073 100644 --- a/pkg/api/ui/dist/core-scm.js +++ b/pkg/api/ui/dist/core-scm.js @@ -3,18 +3,18 @@ * Copyright 2019 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const J = globalThis, ie = J.ShadowRoot && (J.ShadyCSS === void 0 || J.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, re = Symbol(), ne = /* @__PURE__ */ new WeakMap(); -let ye = class { - constructor(e, s, r) { - if (this._$cssResult$ = !0, r !== re) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); +const K = globalThis, re = K.ShadowRoot && (K.ShadyCSS === void 0 || K.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, ie = Symbol(), ne = /* @__PURE__ */ new WeakMap(); +let ve = class { + constructor(e, s, i) { + if (this._$cssResult$ = !0, i !== ie) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); this.cssText = e, this.t = s; } get styleSheet() { let e = this.o; const s = this.t; - if (ie && e === void 0) { - const r = s !== void 0 && s.length === 1; - r && (e = ne.get(s)), e === void 0 && ((this.o = e = new CSSStyleSheet()).replaceSync(this.cssText), r && ne.set(s, e)); + if (re && e === void 0) { + const i = s !== void 0 && s.length === 1; + i && (e = ne.get(s)), e === void 0 && ((this.o = e = new CSSStyleSheet()).replaceSync(this.cssText), i && ne.set(s, e)); } return e; } @@ -22,30 +22,30 @@ let ye = class { return this.cssText; } }; -const xe = (t) => new ye(typeof t == "string" ? t : t + "", void 0, re), W = (t, ...e) => { - const s = t.length === 1 ? t[0] : e.reduce((r, i, o) => r + ((a) => { +const Ae = (t) => new ve(typeof t == "string" ? t : t + "", void 0, ie), B = (t, ...e) => { + const s = t.length === 1 ? t[0] : e.reduce((i, r, o) => i + ((a) => { if (a._$cssResult$ === !0) return a.cssText; if (typeof a == "number") return a; throw Error("Value passed to 'css' function must be a 'css' function result: " + a + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security."); - })(i) + t[o + 1], t[0]); - return new ye(s, t, re); + })(r) + t[o + 1], t[0]); + return new ve(s, t, ie); }, Se = (t, e) => { - if (ie) t.adoptedStyleSheets = e.map((s) => s instanceof CSSStyleSheet ? s : s.styleSheet); + if (re) t.adoptedStyleSheets = e.map((s) => s instanceof CSSStyleSheet ? s : s.styleSheet); else for (const s of e) { - const r = document.createElement("style"), i = J.litNonce; - i !== void 0 && r.setAttribute("nonce", i), r.textContent = s.cssText, t.appendChild(r); + const i = document.createElement("style"), r = K.litNonce; + r !== void 0 && i.setAttribute("nonce", r), i.textContent = s.cssText, t.appendChild(i); } -}, le = ie ? (t) => t : (t) => t instanceof CSSStyleSheet ? ((e) => { +}, le = re ? (t) => t : (t) => t instanceof CSSStyleSheet ? ((e) => { let s = ""; - for (const r of e.cssRules) s += r.cssText; - return xe(s); + for (const i of e.cssRules) s += i.cssText; + return Ae(s); })(t) : t; /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const { is: Ee, defineProperty: Ce, getOwnPropertyDescriptor: ke, getOwnPropertyNames: Pe, getOwnPropertySymbols: Ue, getPrototypeOf: Oe } = Object, A = globalThis, de = A.trustedTypes, Re = de ? de.emptyScript : "", Y = A.reactiveElementPolyfillSupport, D = (t, e) => t, Q = { toAttribute(t, e) { +const { is: Ce, defineProperty: Ee, getOwnPropertyDescriptor: Ue, getOwnPropertyNames: Pe, getOwnPropertySymbols: Oe, getPrototypeOf: ze } = Object, k = globalThis, de = k.trustedTypes, Re = de ? de.emptyScript : "", X = k.reactiveElementPolyfillSupport, H = (t, e) => t, J = { toAttribute(t, e) { switch (e) { case Boolean: t = t ? Re : null; @@ -73,8 +73,8 @@ const { is: Ee, defineProperty: Ce, getOwnPropertyDescriptor: ke, getOwnProperty } } return s; -} }, ae = (t, e) => !Ee(t, e), ce = { attribute: !0, type: String, converter: Q, reflect: !1, useDefault: !1, hasChanged: ae }; -Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), A.litPropertyMetadata ?? (A.litPropertyMetadata = /* @__PURE__ */ new WeakMap()); +} }, ae = (t, e) => !Ce(t, e), ce = { attribute: !0, type: String, converter: J, reflect: !1, useDefault: !1, hasChanged: ae }; +Symbol.metadata ?? (Symbol.metadata = Symbol("metadata")), k.litPropertyMetadata ?? (k.litPropertyMetadata = /* @__PURE__ */ new WeakMap()); let R = class extends HTMLElement { static addInitializer(e) { this._$Ei(), (this.l ?? (this.l = [])).push(e); @@ -84,58 +84,58 @@ let R = class extends HTMLElement { } static createProperty(e, s = ce) { if (s.state && (s.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(e) && ((s = Object.create(s)).wrapped = !0), this.elementProperties.set(e, s), !s.noAccessor) { - const r = Symbol(), i = this.getPropertyDescriptor(e, r, s); - i !== void 0 && Ce(this.prototype, e, i); + const i = Symbol(), r = this.getPropertyDescriptor(e, i, s); + r !== void 0 && Ee(this.prototype, e, r); } } - static getPropertyDescriptor(e, s, r) { - const { get: i, set: o } = ke(this.prototype, e) ?? { get() { + static getPropertyDescriptor(e, s, i) { + const { get: r, set: o } = Ue(this.prototype, e) ?? { get() { return this[s]; }, set(a) { this[s] = a; } }; - return { get: i, set(a) { - const d = i == null ? void 0 : i.call(this); - o == null || o.call(this, a), this.requestUpdate(e, d, r); + return { get: r, set(a) { + const d = r == null ? void 0 : r.call(this); + o == null || o.call(this, a), this.requestUpdate(e, d, i); }, configurable: !0, enumerable: !0 }; } static getPropertyOptions(e) { return this.elementProperties.get(e) ?? ce; } static _$Ei() { - if (this.hasOwnProperty(D("elementProperties"))) return; - const e = Oe(this); + if (this.hasOwnProperty(H("elementProperties"))) return; + const e = ze(this); e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties); } static finalize() { - if (this.hasOwnProperty(D("finalized"))) return; - if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(D("properties"))) { - const s = this.properties, r = [...Pe(s), ...Ue(s)]; - for (const i of r) this.createProperty(i, s[i]); + if (this.hasOwnProperty(H("finalized"))) return; + if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(H("properties"))) { + const s = this.properties, i = [...Pe(s), ...Oe(s)]; + for (const r of i) this.createProperty(r, s[r]); } const e = this[Symbol.metadata]; if (e !== null) { const s = litPropertyMetadata.get(e); - if (s !== void 0) for (const [r, i] of s) this.elementProperties.set(r, i); + if (s !== void 0) for (const [i, r] of s) this.elementProperties.set(i, r); } this._$Eh = /* @__PURE__ */ new Map(); - for (const [s, r] of this.elementProperties) { - const i = this._$Eu(s, r); - i !== void 0 && this._$Eh.set(i, s); + for (const [s, i] of this.elementProperties) { + const r = this._$Eu(s, i); + r !== void 0 && this._$Eh.set(r, s); } this.elementStyles = this.finalizeStyles(this.styles); } static finalizeStyles(e) { const s = []; if (Array.isArray(e)) { - const r = new Set(e.flat(1 / 0).reverse()); - for (const i of r) s.unshift(le(i)); + const i = new Set(e.flat(1 / 0).reverse()); + for (const r of i) s.unshift(le(r)); } else e !== void 0 && s.push(le(e)); return s; } static _$Eu(e, s) { - const r = s.attribute; - return r === !1 ? void 0 : typeof r == "string" ? r : typeof e == "string" ? e.toLowerCase() : void 0; + const i = s.attribute; + return i === !1 ? void 0 : typeof i == "string" ? i : typeof e == "string" ? e.toLowerCase() : void 0; } constructor() { super(), this._$Ep = void 0, this.isUpdatePending = !1, this.hasUpdated = !1, this._$Em = null, this._$Ev(); @@ -154,7 +154,7 @@ let R = class extends HTMLElement { } _$E_() { const e = /* @__PURE__ */ new Map(), s = this.constructor.elementProperties; - for (const r of s.keys()) this.hasOwnProperty(r) && (e.set(r, this[r]), delete this[r]); + for (const i of s.keys()) this.hasOwnProperty(i) && (e.set(i, this[i]), delete this[i]); e.size > 0 && (this._$Ep = e); } createRenderRoot() { @@ -164,8 +164,8 @@ let R = class extends HTMLElement { connectedCallback() { var e; this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(!0), (e = this._$EO) == null || e.forEach((s) => { - var r; - return (r = s.hostConnected) == null ? void 0 : r.call(s); + var i; + return (i = s.hostConnected) == null ? void 0 : i.call(s); }); } enableUpdating(e) { @@ -173,42 +173,42 @@ let R = class extends HTMLElement { disconnectedCallback() { var e; (e = this._$EO) == null || e.forEach((s) => { - var r; - return (r = s.hostDisconnected) == null ? void 0 : r.call(s); + var i; + return (i = s.hostDisconnected) == null ? void 0 : i.call(s); }); } - attributeChangedCallback(e, s, r) { - this._$AK(e, r); + attributeChangedCallback(e, s, i) { + this._$AK(e, i); } _$ET(e, s) { var o; - const r = this.constructor.elementProperties.get(e), i = this.constructor._$Eu(e, r); - if (i !== void 0 && r.reflect === !0) { - const a = (((o = r.converter) == null ? void 0 : o.toAttribute) !== void 0 ? r.converter : Q).toAttribute(s, r.type); - this._$Em = e, a == null ? this.removeAttribute(i) : this.setAttribute(i, a), this._$Em = null; + const i = this.constructor.elementProperties.get(e), r = this.constructor._$Eu(e, i); + if (r !== void 0 && i.reflect === !0) { + const a = (((o = i.converter) == null ? void 0 : o.toAttribute) !== void 0 ? i.converter : J).toAttribute(s, i.type); + this._$Em = e, a == null ? this.removeAttribute(r) : this.setAttribute(r, a), this._$Em = null; } } _$AK(e, s) { var o, a; - const r = this.constructor, i = r._$Eh.get(e); - if (i !== void 0 && this._$Em !== i) { - const d = r.getPropertyOptions(i), n = typeof d.converter == "function" ? { fromAttribute: d.converter } : ((o = d.converter) == null ? void 0 : o.fromAttribute) !== void 0 ? d.converter : Q; - this._$Em = i; - const u = n.fromAttribute(s, d.type); - this[i] = u ?? ((a = this._$Ej) == null ? void 0 : a.get(i)) ?? u, this._$Em = null; + const i = this.constructor, r = i._$Eh.get(e); + if (r !== void 0 && this._$Em !== r) { + const d = i.getPropertyOptions(r), n = typeof d.converter == "function" ? { fromAttribute: d.converter } : ((o = d.converter) == null ? void 0 : o.fromAttribute) !== void 0 ? d.converter : J; + this._$Em = r; + const h = n.fromAttribute(s, d.type); + this[r] = h ?? ((a = this._$Ej) == null ? void 0 : a.get(r)) ?? h, this._$Em = null; } } - requestUpdate(e, s, r, i = !1, o) { + requestUpdate(e, s, i, r = !1, o) { var a; if (e !== void 0) { const d = this.constructor; - if (i === !1 && (o = this[e]), r ?? (r = d.getPropertyOptions(e)), !((r.hasChanged ?? ae)(o, s) || r.useDefault && r.reflect && o === ((a = this._$Ej) == null ? void 0 : a.get(e)) && !this.hasAttribute(d._$Eu(e, r)))) return; - this.C(e, s, r); + if (r === !1 && (o = this[e]), i ?? (i = d.getPropertyOptions(e)), !((i.hasChanged ?? ae)(o, s) || i.useDefault && i.reflect && o === ((a = this._$Ej) == null ? void 0 : a.get(e)) && !this.hasAttribute(d._$Eu(e, i)))) return; + this.C(e, s, i); } this.isUpdatePending === !1 && (this._$ES = this._$EP()); } - C(e, s, { useDefault: r, reflect: i, wrapped: o }, a) { - r && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(e) && (this._$Ej.set(e, a ?? s ?? this[e]), o !== !0 || a !== void 0) || (this._$AL.has(e) || (this.hasUpdated || r || (s = void 0), this._$AL.set(e, s)), i === !0 && this._$Em !== e && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(e)); + C(e, s, { useDefault: i, reflect: r, wrapped: o }, a) { + i && !(this._$Ej ?? (this._$Ej = /* @__PURE__ */ new Map())).has(e) && (this._$Ej.set(e, a ?? s ?? this[e]), o !== !0 || a !== void 0) || (this._$AL.has(e) || (this.hasUpdated || i || (s = void 0), this._$AL.set(e, s)), r === !0 && this._$Em !== e && (this._$Eq ?? (this._$Eq = /* @__PURE__ */ new Set())).add(e)); } async _$EP() { this.isUpdatePending = !0; @@ -224,15 +224,15 @@ let R = class extends HTMLElement { return this.performUpdate(); } performUpdate() { - var r; + var i; if (!this.isUpdatePending) return; if (!this.hasUpdated) { if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { for (const [o, a] of this._$Ep) this[o] = a; this._$Ep = void 0; } - const i = this.constructor.elementProperties; - if (i.size > 0) for (const [o, a] of i) { + const r = this.constructor.elementProperties; + if (r.size > 0) for (const [o, a] of r) { const { wrapped: d } = a, n = this[o]; d !== !0 || this._$AL.has(o) || n === void 0 || this.C(o, void 0, a, n); } @@ -240,12 +240,12 @@ let R = class extends HTMLElement { let e = !1; const s = this._$AL; try { - e = this.shouldUpdate(s), e ? (this.willUpdate(s), (r = this._$EO) == null || r.forEach((i) => { + e = this.shouldUpdate(s), e ? (this.willUpdate(s), (i = this._$EO) == null || i.forEach((r) => { var o; - return (o = i.hostUpdate) == null ? void 0 : o.call(i); + return (o = r.hostUpdate) == null ? void 0 : o.call(r); }), this.update(s)) : this._$EM(); - } catch (i) { - throw e = !1, this._$EM(), i; + } catch (r) { + throw e = !1, this._$EM(), r; } e && this._$AE(s); } @@ -253,9 +253,9 @@ let R = class extends HTMLElement { } _$AE(e) { var s; - (s = this._$EO) == null || s.forEach((r) => { - var i; - return (i = r.hostUpdated) == null ? void 0 : i.call(r); + (s = this._$EO) == null || s.forEach((i) => { + var r; + return (r = i.hostUpdated) == null ? void 0 : r.call(i); }), this.hasUpdated || (this.hasUpdated = !0, this.firstUpdated(e)), this.updated(e); } _$EM() { @@ -278,76 +278,76 @@ let R = class extends HTMLElement { firstUpdated(e) { } }; -R.elementStyles = [], R.shadowRootOptions = { mode: "open" }, R[D("elementProperties")] = /* @__PURE__ */ new Map(), R[D("finalized")] = /* @__PURE__ */ new Map(), Y == null || Y({ ReactiveElement: R }), (A.reactiveElementVersions ?? (A.reactiveElementVersions = [])).push("2.1.2"); +R.elementStyles = [], R.shadowRootOptions = { mode: "open" }, R[H("elementProperties")] = /* @__PURE__ */ new Map(), R[H("finalized")] = /* @__PURE__ */ new Map(), X == null || X({ ReactiveElement: R }), (k.reactiveElementVersions ?? (k.reactiveElementVersions = [])).push("2.1.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const I = globalThis, he = (t) => t, Z = I.trustedTypes, pe = Z ? Z.createPolicy("lit-html", { createHTML: (t) => t }) : void 0, $e = "$lit$", w = `lit$${Math.random().toFixed(9).slice(2)}$`, _e = "?" + w, ze = `<${_e}>`, U = document, j = () => U.createComment(""), L = (t) => t === null || typeof t != "object" && typeof t != "function", oe = Array.isArray, Te = (t) => oe(t) || typeof (t == null ? void 0 : t[Symbol.iterator]) == "function", ee = `[ -\f\r]`, H = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, ue = /-->/g, fe = />/g, C = RegExp(`>|${ee}(?:([^\\s"'>=/]+)(${ee}*=${ee}*(?:[^ -\f\r"'\`<>=]|("|')|))|$)`, "g"), me = /'/g, ge = /"/g, we = /^(?:script|style|textarea|title)$/i, Me = (t) => (e, ...s) => ({ _$litType$: t, strings: e, values: s }), l = Me(1), z = Symbol.for("lit-noChange"), c = Symbol.for("lit-nothing"), be = /* @__PURE__ */ new WeakMap(), k = U.createTreeWalker(U, 129); -function Ae(t, e) { +const D = globalThis, pe = (t) => t, Q = D.trustedTypes, he = Q ? Q.createPolicy("lit-html", { createHTML: (t) => t }) : void 0, $e = "$lit$", _ = `lit$${Math.random().toFixed(9).slice(2)}$`, xe = "?" + _, Me = `<${xe}>`, O = document, L = () => O.createComment(""), q = (t) => t === null || typeof t != "object" && typeof t != "function", oe = Array.isArray, Te = (t) => oe(t) || typeof (t == null ? void 0 : t[Symbol.iterator]) == "function", ee = `[ +\f\r]`, j = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, me = /-->/g, ue = />/g, E = RegExp(`>|${ee}(?:([^\\s"'>=/]+)(${ee}*=${ee}*(?:[^ +\f\r"'\`<>=]|("|')|))|$)`, "g"), fe = /'/g, ge = /"/g, we = /^(?:script|style|textarea|title)$/i, Ie = (t) => (e, ...s) => ({ _$litType$: t, strings: e, values: s }), l = Ie(1), M = Symbol.for("lit-noChange"), c = Symbol.for("lit-nothing"), be = /* @__PURE__ */ new WeakMap(), U = O.createTreeWalker(O, 129); +function _e(t, e) { if (!oe(t) || !t.hasOwnProperty("raw")) throw Error("invalid template strings array"); - return pe !== void 0 ? pe.createHTML(e) : e; + return he !== void 0 ? he.createHTML(e) : e; } const Ne = (t, e) => { - const s = t.length - 1, r = []; - let i, o = e === 2 ? "" : e === 3 ? "" : "", a = H; + const s = t.length - 1, i = []; + let r, o = e === 2 ? "" : e === 3 ? "" : "", a = j; for (let d = 0; d < s; d++) { const n = t[d]; - let u, f, h = -1, v = 0; - for (; v < n.length && (a.lastIndex = v, f = a.exec(n), f !== null); ) v = a.lastIndex, a === H ? f[1] === "!--" ? a = ue : f[1] !== void 0 ? a = fe : f[2] !== void 0 ? (we.test(f[2]) && (i = RegExp("" ? (a = i ?? H, h = -1) : f[1] === void 0 ? h = -2 : (h = a.lastIndex - f[2].length, u = f[1], a = f[3] === void 0 ? C : f[3] === '"' ? ge : me) : a === ge || a === me ? a = C : a === ue || a === fe ? a = H : (a = C, i = void 0); - const _ = a === C && t[d + 1].startsWith("/>") ? " " : ""; - o += a === H ? n + ze : h >= 0 ? (r.push(u), n.slice(0, h) + $e + n.slice(h) + w + _) : n + w + (h === -2 ? d : _); + let h, u, p = -1, f = 0; + for (; f < n.length && (a.lastIndex = f, u = a.exec(n), u !== null); ) f = a.lastIndex, a === j ? u[1] === "!--" ? a = me : u[1] !== void 0 ? a = ue : u[2] !== void 0 ? (we.test(u[2]) && (r = RegExp("" ? (a = r ?? j, p = -1) : u[1] === void 0 ? p = -2 : (p = a.lastIndex - u[2].length, h = u[1], a = u[3] === void 0 ? E : u[3] === '"' ? ge : fe) : a === ge || a === fe ? a = E : a === me || a === ue ? a = j : (a = E, r = void 0); + const b = a === E && t[d + 1].startsWith("/>") ? " " : ""; + o += a === j ? n + Me : p >= 0 ? (i.push(h), n.slice(0, p) + $e + n.slice(p) + _ + b) : n + _ + (p === -2 ? d : b); } - return [Ae(t, o + (t[s] || "") + (e === 2 ? "" : e === 3 ? "" : "")), r]; + return [_e(t, o + (t[s] || "") + (e === 2 ? "" : e === 3 ? "" : "")), i]; }; -class q { - constructor({ strings: e, _$litType$: s }, r) { - let i; +class W { + constructor({ strings: e, _$litType$: s }, i) { + let r; this.parts = []; let o = 0, a = 0; - const d = e.length - 1, n = this.parts, [u, f] = Ne(e, s); - if (this.el = q.createElement(u, r), k.currentNode = this.el.content, s === 2 || s === 3) { - const h = this.el.content.firstChild; - h.replaceWith(...h.childNodes); + const d = e.length - 1, n = this.parts, [h, u] = Ne(e, s); + if (this.el = W.createElement(h, i), U.currentNode = this.el.content, s === 2 || s === 3) { + const p = this.el.content.firstChild; + p.replaceWith(...p.childNodes); } - for (; (i = k.nextNode()) !== null && n.length < d; ) { - if (i.nodeType === 1) { - if (i.hasAttributes()) for (const h of i.getAttributeNames()) if (h.endsWith($e)) { - const v = f[a++], _ = i.getAttribute(h).split(w), K = /([.?@])?(.*)/.exec(v); - n.push({ type: 1, index: o, name: K[2], strings: _, ctor: K[1] === "." ? De : K[1] === "?" ? Ie : K[1] === "@" ? je : G }), i.removeAttribute(h); - } else h.startsWith(w) && (n.push({ type: 6, index: o }), i.removeAttribute(h)); - if (we.test(i.tagName)) { - const h = i.textContent.split(w), v = h.length - 1; - if (v > 0) { - i.textContent = Z ? Z.emptyScript : ""; - for (let _ = 0; _ < v; _++) i.append(h[_], j()), k.nextNode(), n.push({ type: 2, index: ++o }); - i.append(h[v], j()); + for (; (r = U.nextNode()) !== null && n.length < d; ) { + if (r.nodeType === 1) { + if (r.hasAttributes()) for (const p of r.getAttributeNames()) if (p.endsWith($e)) { + const f = u[a++], b = r.getAttribute(p).split(_), y = /([.?@])?(.*)/.exec(f); + n.push({ type: 1, index: o, name: y[2], strings: b, ctor: y[1] === "." ? He : y[1] === "?" ? De : y[1] === "@" ? Le : Z }), r.removeAttribute(p); + } else p.startsWith(_) && (n.push({ type: 6, index: o }), r.removeAttribute(p)); + if (we.test(r.tagName)) { + const p = r.textContent.split(_), f = p.length - 1; + if (f > 0) { + r.textContent = Q ? Q.emptyScript : ""; + for (let b = 0; b < f; b++) r.append(p[b], L()), U.nextNode(), n.push({ type: 2, index: ++o }); + r.append(p[f], L()); } } - } else if (i.nodeType === 8) if (i.data === _e) n.push({ type: 2, index: o }); + } else if (r.nodeType === 8) if (r.data === xe) n.push({ type: 2, index: o }); else { - let h = -1; - for (; (h = i.data.indexOf(w, h + 1)) !== -1; ) n.push({ type: 7, index: o }), h += w.length - 1; + let p = -1; + for (; (p = r.data.indexOf(_, p + 1)) !== -1; ) n.push({ type: 7, index: o }), p += _.length - 1; } o++; } } static createElement(e, s) { - const r = U.createElement("template"); - return r.innerHTML = e, r; + const i = O.createElement("template"); + return i.innerHTML = e, i; } } -function T(t, e, s = t, r) { +function T(t, e, s = t, i) { var a, d; - if (e === z) return e; - let i = r !== void 0 ? (a = s._$Co) == null ? void 0 : a[r] : s._$Cl; - const o = L(e) ? void 0 : e._$litDirective$; - return (i == null ? void 0 : i.constructor) !== o && ((d = i == null ? void 0 : i._$AO) == null || d.call(i, !1), o === void 0 ? i = void 0 : (i = new o(t), i._$AT(t, s, r)), r !== void 0 ? (s._$Co ?? (s._$Co = []))[r] = i : s._$Cl = i), i !== void 0 && (e = T(t, i._$AS(t, e.values), i, r)), e; + if (e === M) return e; + let r = i !== void 0 ? (a = s._$Co) == null ? void 0 : a[i] : s._$Cl; + const o = q(e) ? void 0 : e._$litDirective$; + return (r == null ? void 0 : r.constructor) !== o && ((d = r == null ? void 0 : r._$AO) == null || d.call(r, !1), o === void 0 ? r = void 0 : (r = new o(t), r._$AT(t, s, i)), i !== void 0 ? (s._$Co ?? (s._$Co = []))[i] = r : s._$Cl = r), r !== void 0 && (e = T(t, r._$AS(t, e.values), r, i)), e; } -class He { +class je { constructor(e, s) { this._$AV = [], this._$AN = void 0, this._$AD = e, this._$AM = s; } @@ -358,30 +358,30 @@ class He { return this._$AM._$AU; } u(e) { - const { el: { content: s }, parts: r } = this._$AD, i = ((e == null ? void 0 : e.creationScope) ?? U).importNode(s, !0); - k.currentNode = i; - let o = k.nextNode(), a = 0, d = 0, n = r[0]; + const { el: { content: s }, parts: i } = this._$AD, r = ((e == null ? void 0 : e.creationScope) ?? O).importNode(s, !0); + U.currentNode = r; + let o = U.nextNode(), a = 0, d = 0, n = i[0]; for (; n !== void 0; ) { if (a === n.index) { - let u; - n.type === 2 ? u = new V(o, o.nextSibling, this, e) : n.type === 1 ? u = new n.ctor(o, n.name, n.strings, this, e) : n.type === 6 && (u = new Le(o, this, e)), this._$AV.push(u), n = r[++d]; + let h; + n.type === 2 ? h = new F(o, o.nextSibling, this, e) : n.type === 1 ? h = new n.ctor(o, n.name, n.strings, this, e) : n.type === 6 && (h = new qe(o, this, e)), this._$AV.push(h), n = i[++d]; } - a !== (n == null ? void 0 : n.index) && (o = k.nextNode(), a++); + a !== (n == null ? void 0 : n.index) && (o = U.nextNode(), a++); } - return k.currentNode = U, i; + return U.currentNode = O, r; } p(e) { let s = 0; - for (const r of this._$AV) r !== void 0 && (r.strings !== void 0 ? (r._$AI(e, r, s), s += r.strings.length - 2) : r._$AI(e[s])), s++; + for (const i of this._$AV) i !== void 0 && (i.strings !== void 0 ? (i._$AI(e, i, s), s += i.strings.length - 2) : i._$AI(e[s])), s++; } } -class V { +class F { get _$AU() { var e; return ((e = this._$AM) == null ? void 0 : e._$AU) ?? this._$Cv; } - constructor(e, s, r, i) { - this.type = 2, this._$AH = c, this._$AN = void 0, this._$AA = e, this._$AB = s, this._$AM = r, this.options = i, this._$Cv = (i == null ? void 0 : i.isConnected) ?? !0; + constructor(e, s, i, r) { + this.type = 2, this._$AH = c, this._$AN = void 0, this._$AA = e, this._$AB = s, this._$AM = i, this.options = r, this._$Cv = (r == null ? void 0 : r.isConnected) ?? !0; } get parentNode() { let e = this._$AA.parentNode; @@ -395,7 +395,7 @@ class V { return this._$AB; } _$AI(e, s = this) { - e = T(this, e, s), L(e) ? e === c || e == null || e === "" ? (this._$AH !== c && this._$AR(), this._$AH = c) : e !== this._$AH && e !== z && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : Te(e) ? this.k(e) : this._(e); + e = T(this, e, s), q(e) ? e === c || e == null || e === "" ? (this._$AH !== c && this._$AR(), this._$AH = c) : e !== this._$AH && e !== M && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : Te(e) ? this.k(e) : this._(e); } O(e) { return this._$AA.parentNode.insertBefore(e, this._$AB); @@ -404,33 +404,33 @@ class V { this._$AH !== e && (this._$AR(), this._$AH = this.O(e)); } _(e) { - this._$AH !== c && L(this._$AH) ? this._$AA.nextSibling.data = e : this.T(U.createTextNode(e)), this._$AH = e; + this._$AH !== c && q(this._$AH) ? this._$AA.nextSibling.data = e : this.T(O.createTextNode(e)), this._$AH = e; } $(e) { var o; - const { values: s, _$litType$: r } = e, i = typeof r == "number" ? this._$AC(e) : (r.el === void 0 && (r.el = q.createElement(Ae(r.h, r.h[0]), this.options)), r); - if (((o = this._$AH) == null ? void 0 : o._$AD) === i) this._$AH.p(s); + const { values: s, _$litType$: i } = e, r = typeof i == "number" ? this._$AC(e) : (i.el === void 0 && (i.el = W.createElement(_e(i.h, i.h[0]), this.options)), i); + if (((o = this._$AH) == null ? void 0 : o._$AD) === r) this._$AH.p(s); else { - const a = new He(i, this), d = a.u(this.options); + const a = new je(r, this), d = a.u(this.options); a.p(s), this.T(d), this._$AH = a; } } _$AC(e) { let s = be.get(e.strings); - return s === void 0 && be.set(e.strings, s = new q(e)), s; + return s === void 0 && be.set(e.strings, s = new W(e)), s; } k(e) { oe(this._$AH) || (this._$AH = [], this._$AR()); const s = this._$AH; - let r, i = 0; - for (const o of e) i === s.length ? s.push(r = new V(this.O(j()), this.O(j()), this, this.options)) : r = s[i], r._$AI(o), i++; - i < s.length && (this._$AR(r && r._$AB.nextSibling, i), s.length = i); + let i, r = 0; + for (const o of e) r === s.length ? s.push(i = new F(this.O(L()), this.O(L()), this, this.options)) : i = s[r], i._$AI(o), r++; + r < s.length && (this._$AR(i && i._$AB.nextSibling, r), s.length = r); } _$AR(e = this._$AA.nextSibling, s) { - var r; - for ((r = this._$AP) == null ? void 0 : r.call(this, !1, !0, s); e !== this._$AB; ) { - const i = he(e).nextSibling; - he(e).remove(), e = i; + var i; + for ((i = this._$AP) == null ? void 0 : i.call(this, !1, !0, s); e !== this._$AB; ) { + const r = pe(e).nextSibling; + pe(e).remove(), e = r; } } setConnected(e) { @@ -438,32 +438,32 @@ class V { this._$AM === void 0 && (this._$Cv = e, (s = this._$AP) == null || s.call(this, e)); } } -class G { +class Z { get tagName() { return this.element.tagName; } get _$AU() { return this._$AM._$AU; } - constructor(e, s, r, i, o) { - this.type = 1, this._$AH = c, this._$AN = void 0, this.element = e, this.name = s, this._$AM = i, this.options = o, r.length > 2 || r[0] !== "" || r[1] !== "" ? (this._$AH = Array(r.length - 1).fill(new String()), this.strings = r) : this._$AH = c; + constructor(e, s, i, r, o) { + this.type = 1, this._$AH = c, this._$AN = void 0, this.element = e, this.name = s, this._$AM = r, this.options = o, i.length > 2 || i[0] !== "" || i[1] !== "" ? (this._$AH = Array(i.length - 1).fill(new String()), this.strings = i) : this._$AH = c; } - _$AI(e, s = this, r, i) { + _$AI(e, s = this, i, r) { const o = this.strings; let a = !1; - if (o === void 0) e = T(this, e, s, 0), a = !L(e) || e !== this._$AH && e !== z, a && (this._$AH = e); + if (o === void 0) e = T(this, e, s, 0), a = !q(e) || e !== this._$AH && e !== M, a && (this._$AH = e); else { const d = e; - let n, u; - for (e = o[0], n = 0; n < o.length - 1; n++) u = T(this, d[r + n], s, n), u === z && (u = this._$AH[n]), a || (a = !L(u) || u !== this._$AH[n]), u === c ? e = c : e !== c && (e += (u ?? "") + o[n + 1]), this._$AH[n] = u; + let n, h; + for (e = o[0], n = 0; n < o.length - 1; n++) h = T(this, d[i + n], s, n), h === M && (h = this._$AH[n]), a || (a = !q(h) || h !== this._$AH[n]), h === c ? e = c : e !== c && (e += (h ?? "") + o[n + 1]), this._$AH[n] = h; } - a && !i && this.j(e); + a && !r && this.j(e); } j(e) { e === c ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, e ?? ""); } } -class De extends G { +class He extends Z { constructor() { super(...arguments), this.type = 3; } @@ -471,7 +471,7 @@ class De extends G { this.element[this.name] = e === c ? void 0 : e; } } -class Ie extends G { +class De extends Z { constructor() { super(...arguments), this.type = 4; } @@ -479,23 +479,23 @@ class Ie extends G { this.element.toggleAttribute(this.name, !!e && e !== c); } } -class je extends G { - constructor(e, s, r, i, o) { - super(e, s, r, i, o), this.type = 5; +class Le extends Z { + constructor(e, s, i, r, o) { + super(e, s, i, r, o), this.type = 5; } _$AI(e, s = this) { - if ((e = T(this, e, s, 0) ?? c) === z) return; - const r = this._$AH, i = e === c && r !== c || e.capture !== r.capture || e.once !== r.once || e.passive !== r.passive, o = e !== c && (r === c || i); - i && this.element.removeEventListener(this.name, this, r), o && this.element.addEventListener(this.name, this, e), this._$AH = e; + if ((e = T(this, e, s, 0) ?? c) === M) return; + const i = this._$AH, r = e === c && i !== c || e.capture !== i.capture || e.once !== i.once || e.passive !== i.passive, o = e !== c && (i === c || r); + r && this.element.removeEventListener(this.name, this, i), o && this.element.addEventListener(this.name, this, e), this._$AH = e; } handleEvent(e) { var s; typeof this._$AH == "function" ? this._$AH.call(((s = this.options) == null ? void 0 : s.host) ?? this.element, e) : this._$AH.handleEvent(e); } } -class Le { - constructor(e, s, r) { - this.element = e, this.type = 6, this._$AN = void 0, this._$AM = s, this.options = r; +class qe { + constructor(e, s, i) { + this.element = e, this.type = 6, this._$AN = void 0, this._$AM = s, this.options = i; } get _$AU() { return this._$AM._$AU; @@ -504,16 +504,16 @@ class Le { T(this, e); } } -const te = I.litHtmlPolyfillSupport; -te == null || te(q, V), (I.litHtmlVersions ?? (I.litHtmlVersions = [])).push("3.3.2"); -const qe = (t, e, s) => { - const r = (s == null ? void 0 : s.renderBefore) ?? e; - let i = r._$litPart$; - if (i === void 0) { +const te = D.litHtmlPolyfillSupport; +te == null || te(W, F), (D.litHtmlVersions ?? (D.litHtmlVersions = [])).push("3.3.2"); +const We = (t, e, s) => { + const i = (s == null ? void 0 : s.renderBefore) ?? e; + let r = i._$litPart$; + if (r === void 0) { const o = (s == null ? void 0 : s.renderBefore) ?? null; - r._$litPart$ = i = new V(e.insertBefore(j(), o), o, void 0, s ?? {}); + i._$litPart$ = r = new F(e.insertBefore(L(), o), o, void 0, s ?? {}); } - return i._$AI(t), i; + return r._$AI(t), r; }; /** * @license @@ -521,7 +521,7 @@ const qe = (t, e, s) => { * SPDX-License-Identifier: BSD-3-Clause */ const P = globalThis; -class y extends R { +class x extends R { constructor() { super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0; } @@ -532,7 +532,7 @@ class y extends R { } update(e) { const s = this.render(); - this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(e), this._$Do = qe(s, this.renderRoot, this.renderOptions); + this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(e), this._$Do = We(s, this.renderRoot, this.renderOptions); } connectedCallback() { var e; @@ -543,20 +543,20 @@ class y extends R { super.disconnectedCallback(), (e = this._$Do) == null || e.setConnected(!1); } render() { - return z; + return M; } } -var ve; -y._$litElement$ = !0, y.finalized = !0, (ve = P.litElementHydrateSupport) == null || ve.call(P, { LitElement: y }); +var ye; +x._$litElement$ = !0, x.finalized = !0, (ye = P.litElementHydrateSupport) == null || ye.call(P, { LitElement: x }); const se = P.litElementPolyfillSupport; -se == null || se({ LitElement: y }); +se == null || se({ LitElement: x }); (P.litElementVersions ?? (P.litElementVersions = [])).push("4.2.2"); /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const B = (t) => (e, s) => { +const V = (t) => (e, s) => { s !== void 0 ? s.addInitializer(() => { customElements.define(t, e); }) : customElements.define(t, e); @@ -566,10 +566,10 @@ const B = (t) => (e, s) => { * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -const We = { attribute: !0, type: String, converter: Q, reflect: !1, hasChanged: ae }, Ve = (t = We, e, s) => { - const { kind: r, metadata: i } = s; - let o = globalThis.litPropertyMetadata.get(i); - if (o === void 0 && globalThis.litPropertyMetadata.set(i, o = /* @__PURE__ */ new Map()), r === "setter" && ((t = Object.create(t)).wrapped = !0), o.set(s.name, t), r === "accessor") { +const Be = { attribute: !0, type: String, converter: J, reflect: !1, hasChanged: ae }, Fe = (t = Be, e, s) => { + const { kind: i, metadata: r } = s; + let o = globalThis.litPropertyMetadata.get(r); + if (o === void 0 && globalThis.litPropertyMetadata.set(r, o = /* @__PURE__ */ new Map()), i === "setter" && ((t = Object.create(t)).wrapped = !0), o.set(s.name, t), i === "accessor") { const { name: a } = s; return { set(d) { const n = e.get.call(this); @@ -578,19 +578,19 @@ const We = { attribute: !0, type: String, converter: Q, reflect: !1, hasChanged: return d !== void 0 && this.C(a, void 0, t, d), d; } }; } - if (r === "setter") { + if (i === "setter") { const { name: a } = s; return function(d) { const n = this[a]; e.call(this, d), this.requestUpdate(a, n, t, !0, d); }; } - throw Error("Unsupported decorator location: " + r); + throw Error("Unsupported decorator location: " + i); }; -function $(t) { - return (e, s) => typeof s == "object" ? Ve(t, e, s) : ((r, i, o) => { - const a = i.hasOwnProperty(o); - return i.constructor.createProperty(o, r), a ? Object.getOwnPropertyDescriptor(i, o) : void 0; +function w(t) { + return (e, s) => typeof s == "object" ? Fe(t, e, s) : ((i, r, o) => { + const a = r.hasOwnProperty(o); + return r.constructor.createProperty(o, i), a ? Object.getOwnPropertyDescriptor(r, o) : void 0; })(t, e, s); } /** @@ -598,21 +598,21 @@ function $(t) { * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ -function p(t) { - return $({ ...t, state: !0, attribute: !1 }); +function m(t) { + return w({ ...t, state: !0, attribute: !1 }); } -function Be(t, e) { +function Ve(t, e) { const s = new WebSocket(t); - return s.onmessage = (r) => { - var i, o, a, d; + return s.onmessage = (i) => { + var r, o, a, d; try { - const n = JSON.parse(r.data); - ((o = (i = n.type) == null ? void 0 : i.startsWith) != null && o.call(i, "scm.") || (d = (a = n.channel) == null ? void 0 : a.startsWith) != null && d.call(a, "scm.")) && e(n); + const n = JSON.parse(i.data); + ((o = (r = n.type) == null ? void 0 : r.startsWith) != null && o.call(r, "scm.") || (d = (a = n.channel) == null ? void 0 : a.startsWith) != null && d.call(a, "scm.")) && e(n); } catch { } }, s; } -class X { +class G { constructor(e = "") { this.baseUrl = e; } @@ -621,18 +621,18 @@ class X { } async request(e, s) { var o, a; - const r = await fetch(`${this.base}${e}`, s), i = await r.json().catch(() => null); - if (!r.ok) - throw new Error(((o = i == null ? void 0 : i.error) == null ? void 0 : o.message) ?? `Request failed (${r.status})`); - if (!(i != null && i.success)) - throw new Error(((a = i == null ? void 0 : i.error) == null ? void 0 : a.message) ?? "Request failed"); - return i.data; + const i = await fetch(`${this.base}${e}`, s), r = await i.json().catch(() => null); + if (!i.ok) + throw new Error(((o = r == null ? void 0 : r.error) == null ? void 0 : o.message) ?? `Request failed (${i.status})`); + if (!(r != null && r.success)) + throw new Error(((a = r == null ? void 0 : r.error) == null ? void 0 : a.message) ?? "Request failed"); + return r.data; } marketplace(e, s) { - const r = new URLSearchParams(); - e && r.set("q", e), s && r.set("category", s); - const i = r.toString(); - return this.request(`/marketplace${i ? `?${i}` : ""}`); + const i = new URLSearchParams(); + e && i.set("q", e), s && i.set("category", s); + const r = i.toString(); + return this.request(`/marketplace${r ? `?${r}` : ""}`); } marketplaceItem(e) { return this.request(`/marketplace/${encodeURIComponent(e)}`); @@ -673,17 +673,17 @@ class X { return this.request("/registry"); } } -var Fe = Object.defineProperty, Ke = Object.getOwnPropertyDescriptor, b = (t, e, s, r) => { - for (var i = r > 1 ? void 0 : r ? Ke(e, s) : e, o = t.length - 1, a; o >= 0; o--) - (a = t[o]) && (i = (r ? a(e, s, i) : a(i)) || i); - return r && i && Fe(e, s, i), i; +var Ye = Object.defineProperty, Ke = Object.getOwnPropertyDescriptor, $ = (t, e, s, i) => { + for (var r = i > 1 ? void 0 : i ? Ke(e, s) : e, o = t.length - 1, a; o >= 0; o--) + (a = t[o]) && (r = (i ? a(e, s, r) : a(r)) || r); + return i && r && Ye(e, s, r), r; }; -let m = class extends y { +let g = class extends x { constructor() { super(...arguments), this.apiUrl = "", this.category = "", this.modules = [], this.categories = [], this.searchQuery = "", this.activeCategory = "", this.loading = !0, this.error = "", this.installing = /* @__PURE__ */ new Set(); } connectedCallback() { - super.connectedCallback(), this.api = new X(this.apiUrl), this.activeCategory = this.category, this.loadModules(); + super.connectedCallback(), this.api = new G(this.apiUrl), this.activeCategory = this.category, this.loadModules(); } async loadModules() { this.loading = !0, this.error = ""; @@ -735,67 +735,166 @@ let m = class extends y { } render() { return l` -
- -
- - ${this.categories.length > 0 ? l` -
- ${this.categories.map( - (t) => l` - - ` - )} +
+
+
+ Marketplace + + Browse, filter, and install providers from the current index. + +
+
+
+ ${this.modules.length} + Results
- ` : c} - ${this.error ? l`
${this.error}
` : c} - ${this.loading ? l`
Loading marketplace\u2026
` : this.modules.length === 0 ? l`
No providers found.
` : l` -
- ${this.modules.map( +
+ ${this.categories.length} + Categories +
+
+
+ +
+ + ${this.categories.length > 0 ? l` +
+ ${this.categories.map( (t) => l` -
-
-
-
${t.name}
-
${t.code}
-
- ${t.category ? l`${t.category}` : c} -
-
- - -
-
- ` + + ` )} -
- `} +
+ ` : c} +
+ + ${this.error ? l`
${this.error}
` : c} + ${this.loading ? l`
Loading marketplace\u2026
` : this.modules.length === 0 ? l`
No providers found.
` : l` +
+ ${this.modules.map( + (t) => l` +
+
+
+
+
${t.name}
+
${t.code}
+
+ ${t.category ? l`${t.category}` : c} +
+
${t.repo}
+
+ ${t.sign_key ? "Signed module" : "Unsigned module"} +
+
+
+ + +
+
+ ` + )} +
+ `} +
`; } }; -m.styles = W` +g.styles = B` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; + } + + .shell { + background: rgba(255, 255, 255, 0.84); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; + padding: 1rem; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); + backdrop-filter: blur(12px); + } + + .summary { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #e2e8f0; + } + + .summary-copy { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .summary-title { + font-size: 1rem; + font-weight: 800; + color: #0f172a; + } + + .summary-subtitle { + font-size: 0.8125rem; + color: #64748b; + } + + .summary-stats { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + justify-content: flex-end; + } + + .stat { + min-width: 4.5rem; + padding: 0.55rem 0.75rem; + border-radius: 0.85rem; + background: linear-gradient(180deg, #f8fafc, #eef2ff); + border: 1px solid #e2e8f0; + text-align: center; + } + + .stat-value { + display: block; + font-size: 1rem; + font-weight: 800; + color: #312e81; + line-height: 1; + } + + .stat-label { + display: block; + margin-top: 0.25rem; + font-size: 0.6875rem; + letter-spacing: 0.06em; + text-transform: uppercase; + color: #64748b; } .toolbar { @@ -803,20 +902,26 @@ m.styles = W` gap: 0.5rem; align-items: center; margin-bottom: 1rem; + flex-wrap: wrap; } .search { flex: 1; - padding: 0.5rem 0.75rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; + min-width: 14rem; + padding: 0.7rem 0.9rem; + border: 1px solid #cbd5e1; + border-radius: 0.85rem; font-size: 0.875rem; outline: none; + background: #fff; + transition: + border-color 0.15s ease, + box-shadow 0.15s ease; } .search:focus { - border-colour: #6366f1; - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); + border-color: #6366f1; + box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.12); } .categories { @@ -826,68 +931,128 @@ m.styles = W` } .category-btn { - padding: 0.25rem 0.75rem; - border: 1px solid #e5e7eb; + padding: 0.35rem 0.8rem; + border: 1px solid #e2e8f0; border-radius: 1rem; background: #fff; font-size: 0.75rem; + font-weight: 700; + color: #475569; cursor: pointer; - transition: all 0.15s; + transition: + background 0.15s ease, + color 0.15s ease, + border-color 0.15s ease, + transform 0.15s ease; } .category-btn:hover { - background: #f3f4f6; + background: #f8fafc; + transform: translateY(-1px); } .category-btn.active { - background: #6366f1; - colour: #fff; - border-colour: #6366f1; + background: linear-gradient(180deg, #6366f1, #4f46e5); + color: #fff; + border-color: #4f46e5; + box-shadow: 0 6px 16px rgba(99, 102, 241, 0.22); } .grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 0.875rem; margin-top: 1rem; } .card { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 1rem; padding: 1rem; - background: #fff; - transition: box-shadow 0.15s; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + border-color 0.15s ease; + min-height: 10rem; + display: flex; + flex-direction: column; + justify-content: space-between; } .card:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08); + border-color: #c7d2fe; + transform: translateY(-2px); } .card-header { display: flex; justify-content: space-between; align-items: flex-start; - margin-bottom: 0.5rem; + gap: 0.75rem; + margin-bottom: 0.75rem; } .card-name { - font-weight: 600; - font-size: 0.9375rem; + font-weight: 800; + font-size: 0.95rem; + color: #0f172a; + line-height: 1.2; } .card-code { - font-size: 0.75rem; - colour: #6b7280; + margin-top: 0.15rem; + font-size: 0.775rem; + color: #64748b; font-family: monospace; } .card-category { font-size: 0.6875rem; - padding: 0.125rem 0.5rem; - background: #f3f4f6; - border-radius: 1rem; - colour: #6b7280; + padding: 0.2rem 0.5rem; + background: #e0e7ff; + border-radius: 999px; + color: #4338ca; + font-weight: 700; + white-space: nowrap; + } + + .card-repo { + font-size: 0.7875rem; + color: #475569; + font-family: monospace; + word-break: break-word; + margin-bottom: 0.4rem; + } + + .card-sign { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.6875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #166534; + margin-bottom: 0.4rem; + } + + .card-sign::before { + content: ''; + width: 0.45rem; + height: 0.45rem; + border-radius: 999px; + background: #22c55e; + } + + .card-sign.unsigned { + color: #64748b; + } + + .card-sign.unsigned::before { + background: #f59e0b; } .card-actions { @@ -897,18 +1062,24 @@ m.styles = W` } button.install { - padding: 0.375rem 1rem; - background: #6366f1; - colour: #fff; + padding: 0.45rem 1rem; + background: linear-gradient(180deg, #6366f1, #4f46e5); + color: #fff; border: none; - border-radius: 0.375rem; + border-radius: 0.75rem; font-size: 0.8125rem; + font-weight: 700; cursor: pointer; - transition: background 0.15s; + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + background 0.15s ease; + box-shadow: 0 8px 16px rgba(99, 102, 241, 0.2); } button.install:hover { - background: #4f46e5; + background: linear-gradient(180deg, #4f46e5, #4338ca); + transform: translateY(-1px); } button.install:disabled { @@ -917,81 +1088,108 @@ m.styles = W` } button.remove { - padding: 0.375rem 1rem; + padding: 0.45rem 1rem; background: #fff; - colour: #dc2626; + color: #dc2626; border: 1px solid #dc2626; - border-radius: 0.375rem; + border-radius: 0.75rem; font-size: 0.8125rem; + font-weight: 700; cursor: pointer; + transition: + background 0.15s ease, + transform 0.15s ease; } button.remove:hover { background: #fef2f2; + transform: translateY(-1px); } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; } + + @media (max-width: 720px) { + .shell { + padding: 0.875rem; + border-radius: 0.875rem; + } + + .summary { + flex-direction: column; + align-items: flex-start; + } + + .summary-stats { + justify-content: flex-start; + } + + .toolbar { + flex-direction: column; + align-items: stretch; + } + } `; -b([ - $({ attribute: "api-url" }) -], m.prototype, "apiUrl", 2); -b([ - $() -], m.prototype, "category", 2); -b([ - p() -], m.prototype, "modules", 2); -b([ - p() -], m.prototype, "categories", 2); -b([ - p() -], m.prototype, "searchQuery", 2); -b([ - p() -], m.prototype, "activeCategory", 2); -b([ - p() -], m.prototype, "loading", 2); -b([ - p() -], m.prototype, "error", 2); -b([ - p() -], m.prototype, "installing", 2); -m = b([ - B("core-scm-marketplace") -], m); -var Je = Object.defineProperty, Qe = Object.getOwnPropertyDescriptor, M = (t, e, s, r) => { - for (var i = r > 1 ? void 0 : r ? Qe(e, s) : e, o = t.length - 1, a; o >= 0; o--) - (a = t[o]) && (i = (r ? a(e, s, i) : a(i)) || i); - return r && i && Je(e, s, i), i; +$([ + w({ attribute: "api-url" }) +], g.prototype, "apiUrl", 2); +$([ + w() +], g.prototype, "category", 2); +$([ + m() +], g.prototype, "modules", 2); +$([ + m() +], g.prototype, "categories", 2); +$([ + m() +], g.prototype, "searchQuery", 2); +$([ + m() +], g.prototype, "activeCategory", 2); +$([ + m() +], g.prototype, "loading", 2); +$([ + m() +], g.prototype, "error", 2); +$([ + m() +], g.prototype, "installing", 2); +g = $([ + V("core-scm-marketplace") +], g); +var Je = Object.defineProperty, Qe = Object.getOwnPropertyDescriptor, I = (t, e, s, i) => { + for (var r = i > 1 ? void 0 : i ? Qe(e, s) : e, o = t.length - 1, a; o >= 0; o--) + (a = t[o]) && (r = (i ? a(e, s, r) : a(r)) || r); + return i && r && Je(e, s, r), r; }; -let x = class extends y { +let A = class extends x { constructor() { super(...arguments), this.apiUrl = "", this.modules = [], this.loading = !0, this.error = "", this.updating = /* @__PURE__ */ new Set(); } connectedCallback() { - super.connectedCallback(), this.api = new X(this.apiUrl), this.loadInstalled(); + super.connectedCallback(), this.api = new G(this.apiUrl), this.loadInstalled(); } async loadInstalled() { this.loading = !0, this.error = ""; @@ -1039,65 +1237,133 @@ let x = class extends y { } render() { return this.loading ? l`
Loading installed providers\u2026
` : l` - ${this.error ? l`
${this.error}
` : c} - ${this.modules.length === 0 ? l`
No providers installed.
` : l` -
- ${this.modules.map( +
+
+
+ Installed providers + + Review local modules, update them, or remove stale installs. + +
+
+ ${this.modules.length} + Installed +
+
+ + ${this.error ? l`
${this.error}
` : c} + ${this.modules.length === 0 ? l`
No providers installed.
` : l` +
+ ${this.modules.map( (t) => l` -
-
-
${t.name}
-
- ${t.code} - v${t.version} - Installed ${this.formatDate(t.installed_at)} +
+
+
${t.name}
+
+ ${t.code} + v${t.version} + Installed ${this.formatDate(t.installed_at)} +
+
+ ${t.repo} + entry: ${t.entry_point} +
+
+ ${t.sign_key ? "Signed manifest" : "Unsigned manifest"} +
+
+
+ +
-
- - -
-
- ` + ` )} -
- `} +
+ `} +
`; } }; -x.styles = W` +A.styles = B` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; + } + + .shell { + background: rgba(255, 255, 255, 0.84); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; + padding: 1rem; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); + backdrop-filter: blur(12px); + } + + .summary { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #e2e8f0; + } + + .summary-copy { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .summary-title { + font-size: 1rem; + font-weight: 800; + color: #0f172a; + } + + .summary-subtitle { + font-size: 0.8125rem; + color: #64748b; } .list { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.75rem; } .item { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 1rem; padding: 1rem; - background: #fff; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); display: flex; justify-content: space-between; align-items: center; - transition: box-shadow 0.15s; + gap: 1rem; + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + border-color 0.15s ease; } .item:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08); + border-color: #c7d2fe; + transform: translateY(-2px); } .item-info { @@ -1105,20 +1371,58 @@ x.styles = W` } .item-name { - font-weight: 600; - font-size: 0.9375rem; + font-weight: 800; + font-size: 0.95rem; + color: #0f172a; } .item-meta { font-size: 0.75rem; - colour: #6b7280; - margin-top: 0.25rem; + color: #64748b; + margin-top: 0.35rem; display: flex; gap: 1rem; + flex-wrap: wrap; } .item-code { font-family: monospace; + color: #334155; + font-weight: 700; + } + + .item-repo, + .item-entry { + font-family: monospace; + color: #475569; + word-break: break-word; + } + + .badge { + display: inline-flex; + align-items: center; + gap: 0.3rem; + font-size: 0.6875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #166534; + } + + .badge::before { + content: ''; + width: 0.45rem; + height: 0.45rem; + border-radius: 999px; + background: #22c55e; + } + + .badge.unsigned { + color: #64748b; + } + + .badge.unsigned::before { + background: #f59e0b; } .item-actions { @@ -1127,21 +1431,26 @@ x.styles = W` } button { - padding: 0.375rem 0.75rem; - border-radius: 0.375rem; + padding: 0.45rem 0.85rem; + border-radius: 0.75rem; font-size: 0.8125rem; cursor: pointer; - transition: background 0.15s; + font-weight: 700; + transition: + background 0.15s ease, + transform 0.15s ease, + box-shadow 0.15s ease; } button.update { background: #fff; - colour: #6366f1; + color: #4338ca; border: 1px solid #6366f1; } button.update:hover { background: #eef2ff; + transform: translateY(-1px); } button.update:disabled { @@ -1151,65 +1460,87 @@ x.styles = W` button.remove { background: #fff; - colour: #dc2626; + color: #dc2626; border: 1px solid #dc2626; } button.remove:hover { background: #fef2f2; + transform: translateY(-1px); } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; margin-bottom: 1rem; } + + @media (max-width: 720px) { + .shell { + padding: 0.875rem; + } + + .summary, + .item { + flex-direction: column; + align-items: flex-start; + } + + .item-actions { + width: 100%; + } + + button { + flex: 1; + } + } `; -M([ - $({ attribute: "api-url" }) -], x.prototype, "apiUrl", 2); -M([ - p() -], x.prototype, "modules", 2); -M([ - p() -], x.prototype, "loading", 2); -M([ - p() -], x.prototype, "error", 2); -M([ - p() -], x.prototype, "updating", 2); -x = M([ - B("core-scm-installed") -], x); -var Ze = Object.defineProperty, Ge = Object.getOwnPropertyDescriptor, E = (t, e, s, r) => { - for (var i = r > 1 ? void 0 : r ? Ge(e, s) : e, o = t.length - 1, a; o >= 0; o--) - (a = t[o]) && (i = (r ? a(e, s, i) : a(i)) || i); - return r && i && Ze(e, s, i), i; +I([ + w({ attribute: "api-url" }) +], A.prototype, "apiUrl", 2); +I([ + m() +], A.prototype, "modules", 2); +I([ + m() +], A.prototype, "loading", 2); +I([ + m() +], A.prototype, "error", 2); +I([ + m() +], A.prototype, "updating", 2); +A = I([ + V("core-scm-installed") +], A); +var Ze = Object.defineProperty, Ge = Object.getOwnPropertyDescriptor, C = (t, e, s, i) => { + for (var r = i > 1 ? void 0 : i ? Ge(e, s) : e, o = t.length - 1, a; o >= 0; o--) + (a = t[o]) && (r = (i ? a(e, s, r) : a(r)) || r); + return i && r && Ze(e, s, r), r; }; -let g = class extends y { +let v = class extends x { constructor() { super(...arguments), this.apiUrl = "", this.path = "", this.manifest = null, this.loading = !0, this.error = "", this.verifyKey = "", this.verifyResult = null; } connectedCallback() { - super.connectedCallback(), this.api = new X(this.apiUrl), this.loadManifest(); + super.connectedCallback(), this.api = new G(this.apiUrl), this.loadManifest(); } async loadManifest() { this.loading = !0, this.error = ""; @@ -1257,7 +1588,7 @@ let g = class extends y { (s) => l`
${s.label}
- ${s.items.map((r) => l`
${r}
`)} + ${s.items.map((i) => l`
${i}
`)}
` )} @@ -1266,20 +1597,25 @@ let g = class extends y { `; } render() { + var o, a, d, n, h, u, p, f, b; if (this.loading) return l`
Loading manifest\u2026
`; if (this.error && !this.manifest) return l`
${this.error}
`; if (!this.manifest) return l`
No manifest found. Create a .core/manifest.yaml to get started.
`; - const t = this.manifest, e = !!t.sign; + const t = this.manifest, e = !!t.sign, s = e ? this.verifyResult ? this.verifyResult.valid ? "verified" : "invalid" : "signed" : "unsigned", i = e ? this.verifyResult ? this.verifyResult.valid ? "Verified" : "Invalid" : "Signed" : "Unsigned", r = (((a = (o = t.permissions) == null ? void 0 : o.read) == null ? void 0 : a.length) ?? 0) + (((n = (d = t.permissions) == null ? void 0 : d.write) == null ? void 0 : n.length) ?? 0) + (((u = (h = t.permissions) == null ? void 0 : h.net) == null ? void 0 : u.length) ?? 0) + (((f = (p = t.permissions) == null ? void 0 : p.run) == null ? void 0 : f.length) ?? 0); return l` ${this.error ? l`
${this.error}
` : c}
-
+

${t.name}

- ${t.code} +
+ ${t.code} + ${r} permissions + ${(b = t.modules) != null && b.length ? l`${t.modules.length} modules` : c} +
v${t.version}
@@ -1301,9 +1637,9 @@ let g = class extends y {
Slots
${Object.entries(t.slots).map( - ([s, r]) => l` - ${s} - ${r} + ([y, ke]) => l` + ${y} + ${ke} ` )}
@@ -1314,15 +1650,16 @@ let g = class extends y { ${t.modules && t.modules.length > 0 ? l`
Modules
- ${t.modules.map((s) => l`
${s}
`)} + ${t.modules.map((y) => l`
${y}
`)}
` : c} -
- - ${e ? this.verifyResult ? this.verifyResult.valid ? "Verified" : "Invalid" : "Signed" : "Unsigned"} +
+ ${i} + + + ${e ? l`Signature present` : l`No signature`} - ${e ? l`Signature present` : l`No signature`}
@@ -1331,7 +1668,7 @@ let g = class extends y { class="verify-input" placeholder="Public key (hex)\u2026" .value=${this.verifyKey} - @input=${(s) => this.verifyKey = s.target.value} + @input=${(y) => this.verifyKey = y.target.value} /> @@ -1340,48 +1677,85 @@ let g = class extends y { `; } }; -g.styles = W` +v.styles = B` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; } .manifest { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; padding: 1.25rem; - background: #fff; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); } .header { display: flex; justify-content: space-between; align-items: flex-start; + gap: 1rem; margin-bottom: 1rem; + padding-bottom: 0.9rem; + border-bottom: 1px solid #e2e8f0; + } + + .header-copy { + display: flex; + flex-direction: column; + gap: 0.35rem; } h3 { margin: 0; - font-size: 1.125rem; - font-weight: 600; + font-size: 1.2rem; + font-weight: 800; + color: #0f172a; } .version { font-size: 0.75rem; - padding: 0.125rem 0.5rem; - background: #f3f4f6; - border-radius: 1rem; - colour: #6b7280; + padding: 0.25rem 0.625rem; + background: #eef2ff; + border-radius: 999px; + color: #4338ca; + font-weight: 700; + } + + .meta-row { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + } + + .meta-chip { + display: inline-flex; + align-items: center; + gap: 0.35rem; + padding: 0.25rem 0.6rem; + border-radius: 999px; + background: #f8fafc; + border: 1px solid #e2e8f0; + font-size: 0.6875rem; + font-weight: 700; + color: #475569; + text-transform: uppercase; + letter-spacing: 0.05em; } .field { - margin-bottom: 0.75rem; + margin-bottom: 0.875rem; } .field-label { font-size: 0.75rem; - font-weight: 600; - colour: #6b7280; + font-weight: 800; + color: #64748b; text-transform: uppercase; letter-spacing: 0.025em; margin-bottom: 0.25rem; @@ -1389,14 +1763,17 @@ g.styles = W` .field-value { font-size: 0.875rem; + color: #0f172a; } .code { font-family: monospace; font-size: 0.8125rem; - background: #f9fafb; - padding: 0.25rem 0.5rem; - border-radius: 0.25rem; + background: #f8fafc; + padding: 0.35rem 0.55rem; + border-radius: 0.45rem; + border: 1px solid #e2e8f0; + color: #1f2937; } .slots { @@ -1404,16 +1781,20 @@ g.styles = W` grid-template-columns: auto 1fr; gap: 0.25rem 1rem; font-size: 0.8125rem; + background: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 0.75rem; + padding: 0.75rem; } .slot-key { - font-weight: 600; - colour: #374151; + font-weight: 700; + color: #334155; } .slot-value { font-family: monospace; - colour: #6b7280; + color: #64748b; } .permissions-grid { @@ -1423,15 +1804,16 @@ g.styles = W` } .perm-group { - border: 1px solid #e5e7eb; - border-radius: 0.375rem; + border: 1px solid #e2e8f0; + border-radius: 0.75rem; padding: 0.5rem; + background: #fff; } .perm-group-label { font-size: 0.6875rem; - font-weight: 700; - colour: #6b7280; + font-weight: 800; + color: #64748b; text-transform: uppercase; margin-bottom: 0.25rem; } @@ -1439,7 +1821,8 @@ g.styles = W` .perm-item { font-size: 0.8125rem; font-family: monospace; - colour: #374151; + color: #374151; + word-break: break-word; } .signature { @@ -1448,8 +1831,9 @@ g.styles = W` gap: 0.75rem; margin-top: 1rem; padding: 0.75rem; - border-radius: 0.375rem; + border-radius: 0.75rem; font-size: 0.875rem; + font-weight: 600; } .signature.signed { @@ -1469,121 +1853,179 @@ g.styles = W` .badge { font-size: 0.75rem; - font-weight: 600; - padding: 0.125rem 0.5rem; - border-radius: 1rem; + font-weight: 800; + padding: 0.25rem 0.55rem; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 0.04em; } .badge.verified { background: #dcfce7; - colour: #166534; + color: #166534; + } + + .badge.signed { + background: #e0e7ff; + color: #4338ca; } .badge.unsigned { background: #fef3c7; - colour: #92400e; + color: #92400e; } .badge.invalid { background: #fee2e2; - colour: #991b1b; + color: #991b1b; } .actions { margin-top: 1rem; display: flex; gap: 0.5rem; + flex-wrap: wrap; } .verify-input { flex: 1; - padding: 0.375rem 0.75rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; + min-width: 14rem; + padding: 0.6rem 0.85rem; + border: 1px solid #cbd5e1; + border-radius: 0.75rem; font-size: 0.8125rem; font-family: monospace; + background: #fff; } button { - padding: 0.375rem 1rem; - border-radius: 0.375rem; + padding: 0.6rem 1rem; + border-radius: 0.75rem; font-size: 0.8125rem; cursor: pointer; border: 1px solid #d1d5db; background: #fff; - transition: background 0.15s; + transition: + background 0.15s ease, + transform 0.15s ease; } button:hover { background: #f3f4f6; + transform: translateY(-1px); } button.primary { - background: #6366f1; - colour: #fff; - border-colour: #6366f1; + background: linear-gradient(180deg, #6366f1, #4f46e5); + color: #fff; + border-color: #6366f1; } button.primary:hover { - background: #4f46e5; + background: linear-gradient(180deg, #4f46e5, #4338ca); } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; + margin-bottom: 0.75rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; + } + + .status { + display: flex; + align-items: center; + gap: 0.35rem; + } + + .status-dot { + width: 0.5rem; + height: 0.5rem; + border-radius: 999px; + } + + .status-dot.verified { + background: #22c55e; + } + + .status-dot.signed { + background: #6366f1; + } + + .status-dot.unsigned { + background: #f59e0b; + } + + .status-dot.invalid { + background: #ef4444; + } + + @media (max-width: 720px) { + .manifest { + padding: 1rem; + } + + .header { + flex-direction: column; + align-items: flex-start; + } + + .actions { + flex-direction: column; + } } `; -E([ - $({ attribute: "api-url" }) -], g.prototype, "apiUrl", 2); -E([ - $() -], g.prototype, "path", 2); -E([ - p() -], g.prototype, "manifest", 2); -E([ - p() -], g.prototype, "loading", 2); -E([ - p() -], g.prototype, "error", 2); -E([ - p() -], g.prototype, "verifyKey", 2); -E([ - p() -], g.prototype, "verifyResult", 2); -g = E([ - B("core-scm-manifest") -], g); -var Xe = Object.defineProperty, Ye = Object.getOwnPropertyDescriptor, F = (t, e, s, r) => { - for (var i = r > 1 ? void 0 : r ? Ye(e, s) : e, o = t.length - 1, a; o >= 0; o--) - (a = t[o]) && (i = (r ? a(e, s, i) : a(i)) || i); - return r && i && Xe(e, s, i), i; +C([ + w({ attribute: "api-url" }) +], v.prototype, "apiUrl", 2); +C([ + w() +], v.prototype, "path", 2); +C([ + m() +], v.prototype, "manifest", 2); +C([ + m() +], v.prototype, "loading", 2); +C([ + m() +], v.prototype, "error", 2); +C([ + m() +], v.prototype, "verifyKey", 2); +C([ + m() +], v.prototype, "verifyResult", 2); +v = C([ + V("core-scm-manifest") +], v); +var Xe = Object.defineProperty, et = Object.getOwnPropertyDescriptor, Y = (t, e, s, i) => { + for (var r = i > 1 ? void 0 : i ? et(e, s) : e, o = t.length - 1, a; o >= 0; o--) + (a = t[o]) && (r = (i ? a(e, s, r) : a(r)) || r); + return i && r && Xe(e, s, r), r; }; -let O = class extends y { +let z = class extends x { constructor() { super(...arguments), this.apiUrl = "", this.repos = [], this.loading = !0, this.error = ""; } connectedCallback() { - super.connectedCallback(), this.api = new X(this.apiUrl), this.loadRegistry(); + super.connectedCallback(), this.api = new G(this.apiUrl), this.loadRegistry(); } async loadRegistry() { this.loading = !0, this.error = ""; @@ -1600,52 +2042,109 @@ let O = class extends y { } render() { return this.loading ? l`
Loading registry\u2026
` : l` - ${this.error ? l`
${this.error}
` : c} - ${this.repos.length === 0 ? l`
No repositories in registry.
` : l` -
- ${this.repos.map( +
+
+
+ Registry + + Workspace repositories and dependency order from repos.yaml. + +
+
+ ${this.repos.length} + Entries +
+
+ + ${this.error ? l`
${this.error}
` : c} + ${this.repos.length === 0 ? l`
No repositories in registry.
` : l` +
+ ${this.repos.map( (t) => l` -
-
-
${t.name}
- ${t.description ? l`
${t.description}
` : c} -
- ${t.type} - ${t.depends_on && t.depends_on.length > 0 ? l`depends: ${t.depends_on.join(", ")}` : c} +
+
+
${t.name}
+ ${t.description ? l`
${t.description}
` : c} +
+ ${t.type} + ${t.depends_on && t.depends_on.length > 0 ? l`depends: ${t.depends_on.join(", ")}` : c} +
+ ${t.path ? l`
${t.path}
` : c} +
+
+ + ${t.exists ? "Present" : "Missing"}
-
- - ${t.exists ? "Present" : "Missing"} -
-
- ` + ` )} -
- `} +
+ `} +
`; } }; -O.styles = W` +z.styles = B` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; + } + + .shell { + background: rgba(255, 255, 255, 0.84); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; + padding: 1rem; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); + backdrop-filter: blur(12px); + } + + .summary { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #e2e8f0; + } + + .summary-copy { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .summary-title { + font-size: 1rem; + font-weight: 800; + color: #0f172a; + } + + .summary-subtitle { + font-size: 0.8125rem; + color: #64748b; } .list { display: flex; flex-direction: column; - gap: 0.375rem; + gap: 0.625rem; } .repo { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 1rem; padding: 0.75rem 1rem; - background: #fff; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); display: flex; justify-content: space-between; align-items: center; + gap: 1rem; } .repo-info { @@ -1653,14 +2152,15 @@ O.styles = W` } .repo-name { - font-weight: 600; - font-size: 0.9375rem; + font-weight: 800; + font-size: 0.95rem; font-family: monospace; + color: #0f172a; } .repo-desc { font-size: 0.8125rem; - colour: #6b7280; + color: #64748b; margin-top: 0.125rem; } @@ -1669,38 +2169,48 @@ O.styles = W` gap: 0.5rem; align-items: center; margin-top: 0.25rem; + flex-wrap: wrap; } .type-badge { font-size: 0.6875rem; - padding: 0.0625rem 0.5rem; - border-radius: 1rem; - font-weight: 600; + padding: 0.2rem 0.5rem; + border-radius: 999px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.04em; } .type-badge.foundation { background: #dbeafe; - colour: #1e40af; + color: #1e40af; } .type-badge.module { background: #f3e8ff; - colour: #6b21a8; + color: #6b21a8; } .type-badge.product { background: #dcfce7; - colour: #166534; + color: #166534; } .type-badge.template { background: #fef3c7; - colour: #92400e; + color: #92400e; } .deps { font-size: 0.75rem; - colour: #9ca3af; + color: #64748b; + } + + .path { + font-size: 0.75rem; + font-family: monospace; + color: #475569; + word-break: break-word; } .status { @@ -1717,60 +2227,76 @@ O.styles = W` .status-dot.present { background: #22c55e; + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.15); } .status-dot.missing { background: #ef4444; + box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.14); } .status-label { font-size: 0.75rem; - colour: #6b7280; + color: #64748b; + font-weight: 700; } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; margin-bottom: 1rem; } + + @media (max-width: 720px) { + .shell { + padding: 0.875rem; + } + + .summary, + .repo { + flex-direction: column; + align-items: flex-start; + } + } `; -F([ - $({ attribute: "api-url" }) -], O.prototype, "apiUrl", 2); -F([ - p() -], O.prototype, "repos", 2); -F([ - p() -], O.prototype, "loading", 2); -F([ - p() -], O.prototype, "error", 2); -O = F([ - B("core-scm-registry") -], O); -var et = Object.defineProperty, tt = Object.getOwnPropertyDescriptor, N = (t, e, s, r) => { - for (var i = r > 1 ? void 0 : r ? tt(e, s) : e, o = t.length - 1, a; o >= 0; o--) - (a = t[o]) && (i = (r ? a(e, s, i) : a(i)) || i); - return r && i && et(e, s, i), i; +Y([ + w({ attribute: "api-url" }) +], z.prototype, "apiUrl", 2); +Y([ + m() +], z.prototype, "repos", 2); +Y([ + m() +], z.prototype, "loading", 2); +Y([ + m() +], z.prototype, "error", 2); +z = Y([ + V("core-scm-registry") +], z); +var tt = Object.defineProperty, st = Object.getOwnPropertyDescriptor, N = (t, e, s, i) => { + for (var r = i > 1 ? void 0 : i ? st(e, s) : e, o = t.length - 1, a; o >= 0; o--) + (a = t[o]) && (r = (i ? a(e, s, r) : a(r)) || r); + return i && r && tt(e, s, r), r; }; -let S = class extends y { +let S = class extends x { constructor() { super(...arguments), this.apiUrl = "", this.wsUrl = "", this.activeTab = "marketplace", this.wsConnected = !1, this.lastEvent = "", this.ws = null, this.tabs = [ { id: "marketplace", label: "Marketplace" }, @@ -1789,7 +2315,7 @@ let S = class extends y { super.disconnectedCallback(), this.disconnectWs(); } connectWs() { - this.disconnectWs(), this.wsUrl && (this.ws = Be(this.wsUrl, (t) => { + this.disconnectWs(), this.wsUrl && (this.ws = Ve(this.wsUrl, (t) => { this.lastEvent = t.channel ?? t.type ?? "", this.requestUpdate(), this.refreshForEvent(t); }), this.ws.onopen = () => { this.wsConnected = !0; @@ -1835,7 +2361,10 @@ let S = class extends y { const t = this.wsUrl ? this.wsConnected ? "connected" : "disconnected" : "idle"; return l`
- SCM +
+ SCM + Marketplace, manifests, installed modules, and registry status +
@@ -1864,13 +2393,18 @@ let S = class extends y { `; } }; -S.styles = W` +S.styles = B` :host { display: flex; flex-direction: column; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; height: 100%; - background: #fafafa; + background: + radial-gradient(circle at top left, rgba(99, 102, 241, 0.12), transparent 30%), + linear-gradient(180deg, #eef2ff 0%, #f8fafc 28%, #f3f4f6 100%); + color: #111827; } /* H — Header */ @@ -1878,68 +2412,107 @@ S.styles = W` display: flex; justify-content: space-between; align-items: center; - padding: 0.75rem 1rem; - background: #fff; - border-bottom: 1px solid #e5e7eb; + gap: 1rem; + padding: 1rem 1.25rem; + background: rgba(255, 255, 255, 0.86); + backdrop-filter: blur(18px); + border-bottom: 1px solid rgba(226, 232, 240, 0.9); + } + + .title-wrap { + display: flex; + flex-direction: column; + gap: 0.125rem; } .title { - font-weight: 700; font-size: 1rem; - colour: #111827; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #0f172a; + } + + .subtitle { + font-size: 0.8125rem; + color: #64748b; } .refresh-btn { - padding: 0.375rem 0.75rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; - background: #fff; + padding: 0.5rem 0.875rem; + border: 1px solid rgba(99, 102, 241, 0.25); + border-radius: 999px; + background: linear-gradient(180deg, #ffffff, #eef2ff); + color: #4338ca; + font-weight: 600; font-size: 0.8125rem; cursor: pointer; - transition: background 0.15s; + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + background 0.15s ease; + box-shadow: 0 1px 1px rgba(15, 23, 42, 0.04); } .refresh-btn:hover { - background: #f3f4f6; + background: linear-gradient(180deg, #ffffff, #e0e7ff); + transform: translateY(-1px); + box-shadow: 0 8px 20px rgba(99, 102, 241, 0.12); } /* H-L — Tabs */ .tabs { display: flex; - gap: 0; - background: #fff; - border-bottom: 1px solid #e5e7eb; - padding: 0 1rem; + gap: 0.375rem; + padding: 0.75rem 1rem 0; + background: rgba(255, 255, 255, 0.72); + backdrop-filter: blur(18px); + border-bottom: 1px solid rgba(226, 232, 240, 0.9); + overflow-x: auto; } .tab { - padding: 0.625rem 1rem; + padding: 0.7rem 1rem; font-size: 0.8125rem; - font-weight: 500; - colour: #6b7280; + font-weight: 700; + letter-spacing: 0.01em; + color: #64748b; cursor: pointer; - border-bottom: 2px solid transparent; - transition: all 0.15s; - background: none; - border-top: none; - border-left: none; - border-right: none; + border: 1px solid transparent; + border-radius: 999px 999px 0 0; + transition: + color 0.15s ease, + background 0.15s ease, + border-color 0.15s ease, + transform 0.15s ease; + background: transparent; } .tab:hover { - colour: #374151; + color: #334155; + transform: translateY(-1px); } .tab.active { - colour: #6366f1; - border-bottom-colour: #6366f1; + color: #4338ca; + background: rgba(255, 255, 255, 0.96); + border-color: rgba(226, 232, 240, 0.9); + border-bottom-color: rgba(255, 255, 255, 0.96); + box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.6), 0 -8px 24px rgba(15, 23, 42, 0.04); } /* C — Content */ .content { flex: 1; - padding: 1rem; + padding: 1.25rem; overflow-y: auto; + display: flex; + justify-content: center; + align-items: flex-start; + } + + .content > * { + width: min(100%, 1120px); } /* F — Footer / Status bar */ @@ -1947,17 +2520,20 @@ S.styles = W` display: flex; justify-content: space-between; align-items: center; - padding: 0.5rem 1rem; - background: #fff; - border-top: 1px solid #e5e7eb; + gap: 1rem; + padding: 0.75rem 1.25rem; + background: rgba(255, 255, 255, 0.84); + backdrop-filter: blur(18px); + border-top: 1px solid rgba(226, 232, 240, 0.9); font-size: 0.75rem; - colour: #9ca3af; + color: #64748b; } .ws-status { display: flex; align-items: center; gap: 0.375rem; + font-weight: 600; } .ws-dot { @@ -1968,40 +2544,58 @@ S.styles = W` .ws-dot.connected { background: #22c55e; + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.15); } .ws-dot.disconnected { background: #ef4444; + box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.14); } .ws-dot.idle { background: #d1d5db; } + + @media (max-width: 720px) { + .header, + .footer { + flex-direction: column; + align-items: flex-start; + } + + .tabs { + padding-inline: 0.75rem; + } + + .content { + padding: 0.875rem; + } + } `; N([ - $({ attribute: "api-url" }) + w({ attribute: "api-url" }) ], S.prototype, "apiUrl", 2); N([ - $({ attribute: "ws-url" }) + w({ attribute: "ws-url" }) ], S.prototype, "wsUrl", 2); N([ - p() + m() ], S.prototype, "activeTab", 2); N([ - p() + m() ], S.prototype, "wsConnected", 2); N([ - p() + m() ], S.prototype, "lastEvent", 2); S = N([ - B("core-scm-panel") + V("core-scm-panel") ], S); export { - X as ScmApi, - x as ScmInstalled, - g as ScmManifest, - m as ScmMarketplace, + G as ScmApi, + A as ScmInstalled, + v as ScmManifest, + g as ScmMarketplace, S as ScmPanel, - O as ScmRegistry, - Be as connectScmEvents + z as ScmRegistry, + Ve as connectScmEvents }; diff --git a/ui/index.html b/ui/index.html index cf687ba..081d042 100644 --- a/ui/index.html +++ b/ui/index.html @@ -12,15 +12,23 @@ } body { - font-family: system-ui, -apple-system, sans-serif; - background: #f3f4f6; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + background: + radial-gradient(circle at top left, rgba(99, 102, 241, 0.15), transparent 24%), + linear-gradient(180deg, #eef2ff 0%, #f8fafc 30%, #f3f4f6 100%); padding: 2rem; + color: #111827; } h1 { - font-size: 1.5rem; - margin-bottom: 1.5rem; - colour: #111827; + font-size: 1.65rem; + margin: 0 auto 1.5rem; + max-width: 960px; + font-weight: 800; + letter-spacing: -0.03em; + color: #0f172a; } .demo-panel { @@ -28,25 +36,31 @@ max-width: 960px; margin: 0 auto; height: 80vh; - border: 1px solid #d1d5db; - border-radius: 0.5rem; + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; overflow: hidden; + box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08); + background: rgba(255, 255, 255, 0.82); + backdrop-filter: blur(18px); } h2 { font-size: 1.125rem; margin: 2rem auto 1rem; max-width: 960px; - colour: #374151; + color: #374151; + font-weight: 700; } .standalone { max-width: 960px; margin: 0 auto 2rem; - border: 1px solid #d1d5db; - border-radius: 0.5rem; + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; padding: 1rem; - background: #fff; + background: rgba(255, 255, 255, 0.82); + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.05); + backdrop-filter: blur(18px); } diff --git a/ui/src/scm-installed.ts b/ui/src/scm-installed.ts index 56cea05..db04b9c 100644 --- a/ui/src/scm-installed.ts +++ b/ui/src/scm-installed.ts @@ -29,28 +29,74 @@ export class ScmInstalled extends LitElement { static styles = css` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; + } + + .shell { + background: rgba(255, 255, 255, 0.84); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; + padding: 1rem; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); + backdrop-filter: blur(12px); + } + + .summary { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #e2e8f0; + } + + .summary-copy { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .summary-title { + font-size: 1rem; + font-weight: 800; + color: #0f172a; + } + + .summary-subtitle { + font-size: 0.8125rem; + color: #64748b; } .list { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.75rem; } .item { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 1rem; padding: 1rem; - background: #fff; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); display: flex; justify-content: space-between; align-items: center; - transition: box-shadow 0.15s; + gap: 1rem; + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + border-color 0.15s ease; } .item:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); + box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08); + border-color: #c7d2fe; + transform: translateY(-2px); } .item-info { @@ -58,20 +104,58 @@ export class ScmInstalled extends LitElement { } .item-name { - font-weight: 600; - font-size: 0.9375rem; + font-weight: 800; + font-size: 0.95rem; + color: #0f172a; } .item-meta { font-size: 0.75rem; - colour: #6b7280; - margin-top: 0.25rem; + color: #64748b; + margin-top: 0.35rem; display: flex; gap: 1rem; + flex-wrap: wrap; } .item-code { font-family: monospace; + color: #334155; + font-weight: 700; + } + + .item-repo, + .item-entry { + font-family: monospace; + color: #475569; + word-break: break-word; + } + + .badge { + display: inline-flex; + align-items: center; + gap: 0.3rem; + font-size: 0.6875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #166534; + } + + .badge::before { + content: ''; + width: 0.45rem; + height: 0.45rem; + border-radius: 999px; + background: #22c55e; + } + + .badge.unsigned { + color: #64748b; + } + + .badge.unsigned::before { + background: #f59e0b; } .item-actions { @@ -80,21 +164,26 @@ export class ScmInstalled extends LitElement { } button { - padding: 0.375rem 0.75rem; - border-radius: 0.375rem; + padding: 0.45rem 0.85rem; + border-radius: 0.75rem; font-size: 0.8125rem; cursor: pointer; - transition: background 0.15s; + font-weight: 700; + transition: + background 0.15s ease, + transform 0.15s ease, + box-shadow 0.15s ease; } button.update { background: #fff; - colour: #6366f1; + color: #4338ca; border: 1px solid #6366f1; } button.update:hover { background: #eef2ff; + transform: translateY(-1px); } button.update:disabled { @@ -104,35 +193,57 @@ export class ScmInstalled extends LitElement { button.remove { background: #fff; - colour: #dc2626; + color: #dc2626; border: 1px solid #dc2626; } button.remove:hover { background: #fef2f2; + transform: translateY(-1px); } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; margin-bottom: 1rem; } + + @media (max-width: 720px) { + .shell { + padding: 0.875rem; + } + + .summary, + .item { + flex-direction: column; + align-items: flex-start; + } + + .item-actions { + width: 100%; + } + + button { + flex: 1; + } + } `; @property({ attribute: 'api-url' }) apiUrl = ''; @@ -210,39 +321,61 @@ export class ScmInstalled extends LitElement { } return html` - ${this.error ? html`
${this.error}
` : nothing} - ${this.modules.length === 0 - ? html`
No providers installed.
` - : html` -
- ${this.modules.map( - (mod) => html` -
-
-
${mod.name}
-
- ${mod.code} - v${mod.version} - Installed ${this.formatDate(mod.installed_at)} +
+
+
+ Installed providers + + Review local modules, update them, or remove stale installs. + +
+
+ ${this.modules.length} + Installed +
+
+ + ${this.error ? html`
${this.error}
` : nothing} + ${this.modules.length === 0 + ? html`
No providers installed.
` + : html` +
+ ${this.modules.map( + (mod) => html` +
+
+
${mod.name}
+
+ ${mod.code} + v${mod.version} + Installed ${this.formatDate(mod.installed_at)} +
+
+ ${mod.repo} + entry: ${mod.entry_point} +
+
+ ${mod.sign_key ? 'Signed manifest' : 'Unsigned manifest'} +
+
+
+ +
-
- - -
-
- `, - )} -
- `} + `, + )} +
+ `} +
`; } } diff --git a/ui/src/scm-manifest.ts b/ui/src/scm-manifest.ts index 1cbe553..01ed90f 100644 --- a/ui/src/scm-manifest.ts +++ b/ui/src/scm-manifest.ts @@ -29,45 +29,82 @@ export class ScmManifest extends LitElement { static styles = css` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; } .manifest { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; padding: 1.25rem; - background: #fff; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); } .header { display: flex; justify-content: space-between; align-items: flex-start; + gap: 1rem; margin-bottom: 1rem; + padding-bottom: 0.9rem; + border-bottom: 1px solid #e2e8f0; + } + + .header-copy { + display: flex; + flex-direction: column; + gap: 0.35rem; } h3 { margin: 0; - font-size: 1.125rem; - font-weight: 600; + font-size: 1.2rem; + font-weight: 800; + color: #0f172a; } .version { font-size: 0.75rem; - padding: 0.125rem 0.5rem; - background: #f3f4f6; - border-radius: 1rem; - colour: #6b7280; + padding: 0.25rem 0.625rem; + background: #eef2ff; + border-radius: 999px; + color: #4338ca; + font-weight: 700; + } + + .meta-row { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + } + + .meta-chip { + display: inline-flex; + align-items: center; + gap: 0.35rem; + padding: 0.25rem 0.6rem; + border-radius: 999px; + background: #f8fafc; + border: 1px solid #e2e8f0; + font-size: 0.6875rem; + font-weight: 700; + color: #475569; + text-transform: uppercase; + letter-spacing: 0.05em; } .field { - margin-bottom: 0.75rem; + margin-bottom: 0.875rem; } .field-label { font-size: 0.75rem; - font-weight: 600; - colour: #6b7280; + font-weight: 800; + color: #64748b; text-transform: uppercase; letter-spacing: 0.025em; margin-bottom: 0.25rem; @@ -75,14 +112,17 @@ export class ScmManifest extends LitElement { .field-value { font-size: 0.875rem; + color: #0f172a; } .code { font-family: monospace; font-size: 0.8125rem; - background: #f9fafb; - padding: 0.25rem 0.5rem; - border-radius: 0.25rem; + background: #f8fafc; + padding: 0.35rem 0.55rem; + border-radius: 0.45rem; + border: 1px solid #e2e8f0; + color: #1f2937; } .slots { @@ -90,16 +130,20 @@ export class ScmManifest extends LitElement { grid-template-columns: auto 1fr; gap: 0.25rem 1rem; font-size: 0.8125rem; + background: #f8fafc; + border: 1px solid #e2e8f0; + border-radius: 0.75rem; + padding: 0.75rem; } .slot-key { - font-weight: 600; - colour: #374151; + font-weight: 700; + color: #334155; } .slot-value { font-family: monospace; - colour: #6b7280; + color: #64748b; } .permissions-grid { @@ -109,15 +153,16 @@ export class ScmManifest extends LitElement { } .perm-group { - border: 1px solid #e5e7eb; - border-radius: 0.375rem; + border: 1px solid #e2e8f0; + border-radius: 0.75rem; padding: 0.5rem; + background: #fff; } .perm-group-label { font-size: 0.6875rem; - font-weight: 700; - colour: #6b7280; + font-weight: 800; + color: #64748b; text-transform: uppercase; margin-bottom: 0.25rem; } @@ -125,7 +170,8 @@ export class ScmManifest extends LitElement { .perm-item { font-size: 0.8125rem; font-family: monospace; - colour: #374151; + color: #374151; + word-break: break-word; } .signature { @@ -134,8 +180,9 @@ export class ScmManifest extends LitElement { gap: 0.75rem; margin-top: 1rem; padding: 0.75rem; - border-radius: 0.375rem; + border-radius: 0.75rem; font-size: 0.875rem; + font-weight: 600; } .signature.signed { @@ -155,84 +202,142 @@ export class ScmManifest extends LitElement { .badge { font-size: 0.75rem; - font-weight: 600; - padding: 0.125rem 0.5rem; - border-radius: 1rem; + font-weight: 800; + padding: 0.25rem 0.55rem; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 0.04em; } .badge.verified { background: #dcfce7; - colour: #166534; + color: #166534; + } + + .badge.signed { + background: #e0e7ff; + color: #4338ca; } .badge.unsigned { background: #fef3c7; - colour: #92400e; + color: #92400e; } .badge.invalid { background: #fee2e2; - colour: #991b1b; + color: #991b1b; } .actions { margin-top: 1rem; display: flex; gap: 0.5rem; + flex-wrap: wrap; } .verify-input { flex: 1; - padding: 0.375rem 0.75rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; + min-width: 14rem; + padding: 0.6rem 0.85rem; + border: 1px solid #cbd5e1; + border-radius: 0.75rem; font-size: 0.8125rem; font-family: monospace; + background: #fff; } button { - padding: 0.375rem 1rem; - border-radius: 0.375rem; + padding: 0.6rem 1rem; + border-radius: 0.75rem; font-size: 0.8125rem; cursor: pointer; border: 1px solid #d1d5db; background: #fff; - transition: background 0.15s; + transition: + background 0.15s ease, + transform 0.15s ease; } button:hover { background: #f3f4f6; + transform: translateY(-1px); } button.primary { - background: #6366f1; - colour: #fff; - border-colour: #6366f1; + background: linear-gradient(180deg, #6366f1, #4f46e5); + color: #fff; + border-color: #6366f1; } button.primary:hover { - background: #4f46e5; + background: linear-gradient(180deg, #4f46e5, #4338ca); } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; + margin-bottom: 0.75rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; + } + + .status { + display: flex; + align-items: center; + gap: 0.35rem; + } + + .status-dot { + width: 0.5rem; + height: 0.5rem; + border-radius: 999px; + } + + .status-dot.verified { + background: #22c55e; + } + + .status-dot.signed { + background: #6366f1; + } + + .status-dot.unsigned { + background: #f59e0b; + } + + .status-dot.invalid { + background: #ef4444; + } + + @media (max-width: 720px) { + .manifest { + padding: 1rem; + } + + .header { + flex-direction: column; + align-items: flex-start; + } + + .actions { + flex-direction: column; + } } `; @@ -332,14 +437,39 @@ export class ScmManifest extends LitElement { const m = this.manifest; const hasSig = !!m.sign; + const status = hasSig + ? this.verifyResult + ? this.verifyResult.valid + ? 'verified' + : 'invalid' + : 'signed' + : 'unsigned'; + const statusLabel = hasSig + ? this.verifyResult + ? this.verifyResult.valid + ? 'Verified' + : 'Invalid' + : 'Signed' + : 'Unsigned'; + const permissionCount = + (m.permissions?.read?.length ?? 0) + + (m.permissions?.write?.length ?? 0) + + (m.permissions?.net?.length ?? 0) + + (m.permissions?.run?.length ?? 0); return html` ${this.error ? html`
${this.error}
` : nothing}
-
+

${m.name}

- ${m.code} +
+ ${m.code} + ${permissionCount} permissions + ${m.modules?.length + ? html`${m.modules.length} modules` + : nothing} +
v${m.version}
@@ -381,16 +511,17 @@ export class ScmManifest extends LitElement { ? html`
Modules
- ${m.modules.map((mod) => html`
${mod}
`)} + ${m.modules.map((mod) => html`
${mod}
`)}
` : nothing} -
- - ${hasSig ? (this.verifyResult ? (this.verifyResult.valid ? 'Verified' : 'Invalid') : 'Signed') : 'Unsigned'} +
+ ${statusLabel} + + + ${hasSig ? html`Signature present` : html`No signature`} - ${hasSig ? html`Signature present` : html`No signature`}
diff --git a/ui/src/scm-marketplace.ts b/ui/src/scm-marketplace.ts index cee41dc..dbd3672 100644 --- a/ui/src/scm-marketplace.ts +++ b/ui/src/scm-marketplace.ts @@ -21,7 +21,79 @@ export class ScmMarketplace extends LitElement { static styles = css` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; + } + + .shell { + background: rgba(255, 255, 255, 0.84); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; + padding: 1rem; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); + backdrop-filter: blur(12px); + } + + .summary { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #e2e8f0; + } + + .summary-copy { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .summary-title { + font-size: 1rem; + font-weight: 800; + color: #0f172a; + } + + .summary-subtitle { + font-size: 0.8125rem; + color: #64748b; + } + + .summary-stats { + display: flex; + gap: 0.5rem; + flex-wrap: wrap; + justify-content: flex-end; + } + + .stat { + min-width: 4.5rem; + padding: 0.55rem 0.75rem; + border-radius: 0.85rem; + background: linear-gradient(180deg, #f8fafc, #eef2ff); + border: 1px solid #e2e8f0; + text-align: center; + } + + .stat-value { + display: block; + font-size: 1rem; + font-weight: 800; + color: #312e81; + line-height: 1; + } + + .stat-label { + display: block; + margin-top: 0.25rem; + font-size: 0.6875rem; + letter-spacing: 0.06em; + text-transform: uppercase; + color: #64748b; } .toolbar { @@ -29,20 +101,26 @@ export class ScmMarketplace extends LitElement { gap: 0.5rem; align-items: center; margin-bottom: 1rem; + flex-wrap: wrap; } .search { flex: 1; - padding: 0.5rem 0.75rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; + min-width: 14rem; + padding: 0.7rem 0.9rem; + border: 1px solid #cbd5e1; + border-radius: 0.85rem; font-size: 0.875rem; outline: none; + background: #fff; + transition: + border-color 0.15s ease, + box-shadow 0.15s ease; } .search:focus { - border-colour: #6366f1; - box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2); + border-color: #6366f1; + box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.12); } .categories { @@ -52,68 +130,128 @@ export class ScmMarketplace extends LitElement { } .category-btn { - padding: 0.25rem 0.75rem; - border: 1px solid #e5e7eb; + padding: 0.35rem 0.8rem; + border: 1px solid #e2e8f0; border-radius: 1rem; background: #fff; font-size: 0.75rem; + font-weight: 700; + color: #475569; cursor: pointer; - transition: all 0.15s; + transition: + background 0.15s ease, + color 0.15s ease, + border-color 0.15s ease, + transform 0.15s ease; } .category-btn:hover { - background: #f3f4f6; + background: #f8fafc; + transform: translateY(-1px); } .category-btn.active { - background: #6366f1; - colour: #fff; - border-colour: #6366f1; + background: linear-gradient(180deg, #6366f1, #4f46e5); + color: #fff; + border-color: #4f46e5; + box-shadow: 0 6px 16px rgba(99, 102, 241, 0.22); } .grid { display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 1rem; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 0.875rem; margin-top: 1rem; } .card { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 1rem; padding: 1rem; - background: #fff; - transition: box-shadow 0.15s; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + border-color 0.15s ease; + min-height: 10rem; + display: flex; + flex-direction: column; + justify-content: space-between; } .card:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 16px 36px rgba(15, 23, 42, 0.08); + border-color: #c7d2fe; + transform: translateY(-2px); } .card-header { display: flex; justify-content: space-between; align-items: flex-start; - margin-bottom: 0.5rem; + gap: 0.75rem; + margin-bottom: 0.75rem; } .card-name { - font-weight: 600; - font-size: 0.9375rem; + font-weight: 800; + font-size: 0.95rem; + color: #0f172a; + line-height: 1.2; } .card-code { - font-size: 0.75rem; - colour: #6b7280; + margin-top: 0.15rem; + font-size: 0.775rem; + color: #64748b; font-family: monospace; } .card-category { font-size: 0.6875rem; - padding: 0.125rem 0.5rem; - background: #f3f4f6; - border-radius: 1rem; - colour: #6b7280; + padding: 0.2rem 0.5rem; + background: #e0e7ff; + border-radius: 999px; + color: #4338ca; + font-weight: 700; + white-space: nowrap; + } + + .card-repo { + font-size: 0.7875rem; + color: #475569; + font-family: monospace; + word-break: break-word; + margin-bottom: 0.4rem; + } + + .card-sign { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.6875rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #166534; + margin-bottom: 0.4rem; + } + + .card-sign::before { + content: ''; + width: 0.45rem; + height: 0.45rem; + border-radius: 999px; + background: #22c55e; + } + + .card-sign.unsigned { + color: #64748b; + } + + .card-sign.unsigned::before { + background: #f59e0b; } .card-actions { @@ -123,18 +261,24 @@ export class ScmMarketplace extends LitElement { } button.install { - padding: 0.375rem 1rem; - background: #6366f1; - colour: #fff; + padding: 0.45rem 1rem; + background: linear-gradient(180deg, #6366f1, #4f46e5); + color: #fff; border: none; - border-radius: 0.375rem; + border-radius: 0.75rem; font-size: 0.8125rem; + font-weight: 700; cursor: pointer; - transition: background 0.15s; + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + background 0.15s ease; + box-shadow: 0 8px 16px rgba(99, 102, 241, 0.2); } button.install:hover { - background: #4f46e5; + background: linear-gradient(180deg, #4f46e5, #4338ca); + transform: translateY(-1px); } button.install:disabled { @@ -143,39 +287,66 @@ export class ScmMarketplace extends LitElement { } button.remove { - padding: 0.375rem 1rem; + padding: 0.45rem 1rem; background: #fff; - colour: #dc2626; + color: #dc2626; border: 1px solid #dc2626; - border-radius: 0.375rem; + border-radius: 0.75rem; font-size: 0.8125rem; + font-weight: 700; cursor: pointer; + transition: + background 0.15s ease, + transform 0.15s ease; } button.remove:hover { background: #fef2f2; + transform: translateY(-1px); } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; } + + @media (max-width: 720px) { + .shell { + padding: 0.875rem; + border-radius: 0.875rem; + } + + .summary { + flex-direction: column; + align-items: flex-start; + } + + .summary-stats { + justify-content: flex-start; + } + + .toolbar { + flex-direction: column; + align-items: stretch; + } + } `; @property({ attribute: 'api-url' }) apiUrl = ''; @@ -262,68 +433,95 @@ export class ScmMarketplace extends LitElement { render() { return html` -
- -
- - ${this.categories.length > 0 - ? html` -
- ${this.categories.map( - (cat) => html` - - `, - )} +
+
+
+ Marketplace + + Browse, filter, and install providers from the current index. + +
+
+
+ ${this.modules.length} + Results
- ` - : nothing} - ${this.error ? html`
${this.error}
` : nothing} - ${this.loading - ? html`
Loading marketplace\u2026
` - : this.modules.length === 0 - ? html`
No providers found.
` - : html` -
- ${this.modules.map( - (mod) => html` -
-
+
+ ${this.categories.length} + Categories +
+
+
+ +
+ + ${this.categories.length > 0 + ? html` +
+ ${this.categories.map( + (cat) => html` + + `, + )} +
+ ` + : nothing} +
+ + ${this.error ? html`
${this.error}
` : nothing} + ${this.loading + ? html`
Loading marketplace\u2026
` + : this.modules.length === 0 + ? html`
No providers found.
` + : html` +
+ ${this.modules.map( + (mod) => html` +
-
${mod.name}
-
${mod.code}
+
+
+
${mod.name}
+
${mod.code}
+
+ ${mod.category + ? html`${mod.category}` + : nothing} +
+
${mod.repo}
+
+ ${mod.sign_key ? 'Signed module' : 'Unsigned module'} +
+
+
+ +
- ${mod.category - ? html`${mod.category}` - : nothing}
-
- - -
-
- `, - )} -
- `} + `, + )} +
+ `} +
`; } } diff --git a/ui/src/scm-panel.ts b/ui/src/scm-panel.ts index 3b5978d..a2fcd69 100644 --- a/ui/src/scm-panel.ts +++ b/ui/src/scm-panel.ts @@ -31,9 +31,14 @@ export class ScmPanel extends LitElement { :host { display: flex; flex-direction: column; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; height: 100%; - background: #fafafa; + background: + radial-gradient(circle at top left, rgba(99, 102, 241, 0.12), transparent 30%), + linear-gradient(180deg, #eef2ff 0%, #f8fafc 28%, #f3f4f6 100%); + color: #111827; } /* H — Header */ @@ -41,68 +46,107 @@ export class ScmPanel extends LitElement { display: flex; justify-content: space-between; align-items: center; - padding: 0.75rem 1rem; - background: #fff; - border-bottom: 1px solid #e5e7eb; + gap: 1rem; + padding: 1rem 1.25rem; + background: rgba(255, 255, 255, 0.86); + backdrop-filter: blur(18px); + border-bottom: 1px solid rgba(226, 232, 240, 0.9); + } + + .title-wrap { + display: flex; + flex-direction: column; + gap: 0.125rem; } .title { - font-weight: 700; font-size: 1rem; - colour: #111827; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #0f172a; + } + + .subtitle { + font-size: 0.8125rem; + color: #64748b; } .refresh-btn { - padding: 0.375rem 0.75rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; - background: #fff; + padding: 0.5rem 0.875rem; + border: 1px solid rgba(99, 102, 241, 0.25); + border-radius: 999px; + background: linear-gradient(180deg, #ffffff, #eef2ff); + color: #4338ca; + font-weight: 600; font-size: 0.8125rem; cursor: pointer; - transition: background 0.15s; + transition: + transform 0.15s ease, + box-shadow 0.15s ease, + background 0.15s ease; + box-shadow: 0 1px 1px rgba(15, 23, 42, 0.04); } .refresh-btn:hover { - background: #f3f4f6; + background: linear-gradient(180deg, #ffffff, #e0e7ff); + transform: translateY(-1px); + box-shadow: 0 8px 20px rgba(99, 102, 241, 0.12); } /* H-L — Tabs */ .tabs { display: flex; - gap: 0; - background: #fff; - border-bottom: 1px solid #e5e7eb; - padding: 0 1rem; + gap: 0.375rem; + padding: 0.75rem 1rem 0; + background: rgba(255, 255, 255, 0.72); + backdrop-filter: blur(18px); + border-bottom: 1px solid rgba(226, 232, 240, 0.9); + overflow-x: auto; } .tab { - padding: 0.625rem 1rem; + padding: 0.7rem 1rem; font-size: 0.8125rem; - font-weight: 500; - colour: #6b7280; + font-weight: 700; + letter-spacing: 0.01em; + color: #64748b; cursor: pointer; - border-bottom: 2px solid transparent; - transition: all 0.15s; - background: none; - border-top: none; - border-left: none; - border-right: none; + border: 1px solid transparent; + border-radius: 999px 999px 0 0; + transition: + color 0.15s ease, + background 0.15s ease, + border-color 0.15s ease, + transform 0.15s ease; + background: transparent; } .tab:hover { - colour: #374151; + color: #334155; + transform: translateY(-1px); } .tab.active { - colour: #6366f1; - border-bottom-colour: #6366f1; + color: #4338ca; + background: rgba(255, 255, 255, 0.96); + border-color: rgba(226, 232, 240, 0.9); + border-bottom-color: rgba(255, 255, 255, 0.96); + box-shadow: 0 -1px 0 rgba(255, 255, 255, 0.6), 0 -8px 24px rgba(15, 23, 42, 0.04); } /* C — Content */ .content { flex: 1; - padding: 1rem; + padding: 1.25rem; overflow-y: auto; + display: flex; + justify-content: center; + align-items: flex-start; + } + + .content > * { + width: min(100%, 1120px); } /* F — Footer / Status bar */ @@ -110,17 +154,20 @@ export class ScmPanel extends LitElement { display: flex; justify-content: space-between; align-items: center; - padding: 0.5rem 1rem; - background: #fff; - border-top: 1px solid #e5e7eb; + gap: 1rem; + padding: 0.75rem 1.25rem; + background: rgba(255, 255, 255, 0.84); + backdrop-filter: blur(18px); + border-top: 1px solid rgba(226, 232, 240, 0.9); font-size: 0.75rem; - colour: #9ca3af; + color: #64748b; } .ws-status { display: flex; align-items: center; gap: 0.375rem; + font-weight: 600; } .ws-dot { @@ -131,15 +178,33 @@ export class ScmPanel extends LitElement { .ws-dot.connected { background: #22c55e; + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.15); } .ws-dot.disconnected { background: #ef4444; + box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.14); } .ws-dot.idle { background: #d1d5db; } + + @media (max-width: 720px) { + .header, + .footer { + flex-direction: column; + align-items: flex-start; + } + + .tabs { + padding-inline: 0.75rem; + } + + .content { + padding: 0.875rem; + } + } `; @property({ attribute: 'api-url' }) apiUrl = ''; @@ -269,7 +334,10 @@ export class ScmPanel extends LitElement { return html`
- SCM +
+ SCM + Marketplace, manifests, installed modules, and registry status +
diff --git a/ui/src/scm-registry.ts b/ui/src/scm-registry.ts index 5305ff3..eb08528 100644 --- a/ui/src/scm-registry.ts +++ b/ui/src/scm-registry.ts @@ -22,23 +22,64 @@ export class ScmRegistry extends LitElement { static styles = css` :host { display: block; - font-family: system-ui, -apple-system, sans-serif; + font-family: + Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', + sans-serif; + color: #111827; + } + + .shell { + background: rgba(255, 255, 255, 0.84); + border: 1px solid rgba(226, 232, 240, 0.95); + border-radius: 1rem; + padding: 1rem; + box-shadow: 0 18px 40px rgba(15, 23, 42, 0.06); + backdrop-filter: blur(12px); + } + + .summary { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + margin-bottom: 1rem; + padding-bottom: 0.75rem; + border-bottom: 1px solid #e2e8f0; + } + + .summary-copy { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + .summary-title { + font-size: 1rem; + font-weight: 800; + color: #0f172a; + } + + .summary-subtitle { + font-size: 0.8125rem; + color: #64748b; } .list { display: flex; flex-direction: column; - gap: 0.375rem; + gap: 0.625rem; } .repo { - border: 1px solid #e5e7eb; - border-radius: 0.5rem; + border: 1px solid #e2e8f0; + border-radius: 1rem; padding: 0.75rem 1rem; - background: #fff; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(248, 250, 252, 0.98)); display: flex; justify-content: space-between; align-items: center; + gap: 1rem; } .repo-info { @@ -46,14 +87,15 @@ export class ScmRegistry extends LitElement { } .repo-name { - font-weight: 600; - font-size: 0.9375rem; + font-weight: 800; + font-size: 0.95rem; font-family: monospace; + color: #0f172a; } .repo-desc { font-size: 0.8125rem; - colour: #6b7280; + color: #64748b; margin-top: 0.125rem; } @@ -62,38 +104,48 @@ export class ScmRegistry extends LitElement { gap: 0.5rem; align-items: center; margin-top: 0.25rem; + flex-wrap: wrap; } .type-badge { font-size: 0.6875rem; - padding: 0.0625rem 0.5rem; - border-radius: 1rem; - font-weight: 600; + padding: 0.2rem 0.5rem; + border-radius: 999px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.04em; } .type-badge.foundation { background: #dbeafe; - colour: #1e40af; + color: #1e40af; } .type-badge.module { background: #f3e8ff; - colour: #6b21a8; + color: #6b21a8; } .type-badge.product { background: #dcfce7; - colour: #166534; + color: #166534; } .type-badge.template { background: #fef3c7; - colour: #92400e; + color: #92400e; } .deps { font-size: 0.75rem; - colour: #9ca3af; + color: #64748b; + } + + .path { + font-size: 0.75rem; + font-family: monospace; + color: #475569; + word-break: break-word; } .status { @@ -110,38 +162,54 @@ export class ScmRegistry extends LitElement { .status-dot.present { background: #22c55e; + box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.15); } .status-dot.missing { background: #ef4444; + box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.14); } .status-label { font-size: 0.75rem; - colour: #6b7280; + color: #64748b; + font-weight: 700; } .empty { text-align: center; padding: 2rem; - colour: #9ca3af; + color: #64748b; font-size: 0.875rem; } .loading { text-align: center; padding: 2rem; - colour: #6b7280; + color: #64748b; } .error { - colour: #dc2626; + color: #dc2626; padding: 0.75rem; background: #fef2f2; - border-radius: 0.375rem; + border: 1px solid #fecaca; + border-radius: 0.75rem; font-size: 0.875rem; margin-bottom: 1rem; } + + @media (max-width: 720px) { + .shell { + padding: 0.875rem; + } + + .summary, + .repo { + flex-direction: column; + align-items: flex-start; + } + } `; @property({ attribute: 'api-url' }) apiUrl = ''; @@ -180,35 +248,51 @@ export class ScmRegistry extends LitElement { } return html` - ${this.error ? html`
${this.error}
` : nothing} - ${this.repos.length === 0 - ? html`
No repositories in registry.
` - : html` -
- ${this.repos.map( - (repo) => html` -
-
-
${repo.name}
- ${repo.description - ? html`
${repo.description}
` - : nothing} -
- ${repo.type} - ${repo.depends_on && repo.depends_on.length > 0 - ? html`depends: ${repo.depends_on.join(', ')}` +
+
+
+ Registry + + Workspace repositories and dependency order from repos.yaml. + +
+
+ ${this.repos.length} + Entries +
+
+ + ${this.error ? html`
${this.error}
` : nothing} + ${this.repos.length === 0 + ? html`
No repositories in registry.
` + : html` +
+ ${this.repos.map( + (repo) => html` +
+
+
${repo.name}
+ ${repo.description + ? html`
${repo.description}
` : nothing} +
+ ${repo.type} + ${repo.depends_on && repo.depends_on.length > 0 + ? html`depends: ${repo.depends_on.join(', ')}` + : nothing} +
+ ${repo.path ? html`
${repo.path}
` : nothing} +
+
+ + ${repo.exists ? 'Present' : 'Missing'}
-
- - ${repo.exists ? 'Present' : 'Missing'} -
-
- `, - )} -
- `} + `, + )} +
+ `} +
`; } }