The plugin list, grouped by what a plugin actually is

Category has been in the plugin contract since it was written — apis-external,
drives-external, drives-local — and every builtin declared the same one, so it
grouped nothing. Two of the three talk to a wallbox and one talks to a car
manufacturer, and those are different questions an operator arrives with: the
Toyota card is where a driver's account gets linked, the Anker and Greencell
cards are where a charger's broker and credentials live. So vehicles and
chargers join the constants and the three builtins say which they are.

The panel groups on that field rather than on a list of names, which is what
keeps an external plugin from needing panel code. Tab order mirrors the
constants; a category with nothing in it gets no tab, and a single group hides
the bar entirely, so an install with one connector looks exactly as it did.
A category the panel does not recognise — or an empty one — falls to the
external-APIs tab rather than vanishing, because a plugin nobody can see is a
plugin nobody can disable. The selected tab falls back to the first group when
its own goes away, which is what removing the last external plugin does.

Registration still asks only for name, base URL and provider, so a plugin
registered at runtime lands under Other APIs until its manifest names a
category. That path already works and is the honest default: the panel is
guessing about a service it has never spoken to, and the service can say.

The header lockup is the other half. It was a copy of the Web App's mark rather
than the same mark, and copies drift — a 32px icon against 28, a 24px wordmark
against 21.6, "Driver" at text-strong instead of white, "Vault" a step lighter
than brand-400. The Web App's Logo.vue moves in verbatim, props included. The
one thing it cannot inherit is which variant to render: the Web App's rail is
always dark, while this panel flips with its own theme toggle, so on-dark is
bound to the theme and the hand-rolled bar fills that existed to survive that
flip are gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tajniak81andClaude Opus 5 committed 2026-08-29 23:30:56 +02:00
1 parent 340a81b0d6
commit e648634ce1
15 files changed
+120 -45

No files matched your search

+17
View File
@@ -0,0 +1,17 @@
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const r of o.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&n(r)}).observe(document,{childList:!0,subtree:!0});function s(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function n(i){if(i.ep)return;i.ep=!0;const o=s(i);fetch(i.href,o)}})();/**
* @vue/shared v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/function cn(e){const t=Object.create(null);for(const s of e.split(","))t[s]=1;return s=>s in t}const ne={},Tt=[],Ze=()=>{},mi=()=>!1,Ss=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Es=e=>e.startsWith("onUpdate:"),_e=Object.assign,un=(e,t)=>{const s=e.indexOf(t);s>-1&&e.splice(s,1)},$o=Object.prototype.hasOwnProperty,X=(e,t)=>$o.call(e,t),L=Array.isArray,St=e=>ts(e)==="[object Map]",zt=e=>ts(e)==="[object Set]",zn=e=>ts(e)==="[object Date]",W=e=>typeof e=="function",ue=e=>typeof e=="string",Je=e=>typeof e=="symbol",te=e=>e!==null&&typeof e=="object",bi=e=>(te(e)||W(e))&&W(e.then)&&W(e.catch),vi=Object.prototype.toString,ts=e=>vi.call(e),Oo=e=>ts(e).slice(8,-1),yi=e=>ts(e)==="[object Object]",dn=e=>ue(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Bt=cn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Ps=e=>{const t=Object.create(null);return(s=>t[s]||(t[s]=e(s)))},Do=/-\w/g,je=Ps(e=>e.replace(Do,t=>t.slice(1).toUpperCase())),Ro=/\B([A-Z])/g,ft=Ps(e=>e.replace(Ro,"-$1").toLowerCase()),_i=Ps(e=>e.charAt(0).toUpperCase()+e.slice(1)),Ns=Ps(e=>e?`on${_i(e)}`:""),qe=(e,t)=>!Object.is(e,t),ps=(e,...t)=>{for(let s=0;s<e.length;s++)e[s](...t)},wi=(e,t,s,n=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:n,value:s})},Cs=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let In;const As=()=>In||(In=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function pn(e){if(L(e)){const t={};for(let s=0;s<e.length;s++){const n=e[s],i=ue(n)?Uo(n):pn(n);if(i)for(const o in i)t[o]=i[o]}return t}else if(ue(e)||te(e))return e}const zo=/;(?![^(]*\))/g,Io=/:([^]+)/,jo=/\/\*[^]*?\*\//g;function Uo(e){const t={};return e.replace(jo,"").split(zo).forEach(s=>{if(s){const n=s.split(Io);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function Ee(e){let t="";if(ue(e))t=e;else if(L(e))for(let s=0;s<e.length;s++){const n=Ee(e[s]);n&&(t+=n+" ")}else if(te(e))for(const s in e)e[s]&&(t+=s+" ");return t.trim()}const No="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",Mo=cn(No);function xi(e){return!!e||e===""}function Lo(e,t){if(e.length!==t.length)return!1;let s=!0;for(let n=0;s&&n<e.length;n++)s=ut(e[n],t[n]);return s}function ut(e,t){if(e===t)return!0;let s=zn(e),n=zn(t);if(s||n)return s&&n?e.getTime()===t.getTime():!1;if(s=Je(e),n=Je(t),s||n)return e===t;if(s=L(e),n=L(t),s||n)return s&&n?Lo(e,t):!1;if(s=te(e),n=te(t),s||n){if(!s||!n)return!1;const i=Object.keys(e).length,o=Object.keys(t).length;if(i!==o)return!1;for(const r in e){const a=e.hasOwnProperty(r),l=t.hasOwnProperty(r);if(a&&!l||!a&&l||!ut(e[r],t[r]))return!1}}return String(e)===String(t)}function fn(e,t){return e.findIndex(s=>ut(s,t))}const ki=e=>!!(e&&e.__v_isRef===!0),m=e=>ue(e)?e:e==null?"":L(e)||te(e)&&(e.toString===vi||!W(e.toString))?ki(e)?m(e.value):JSON.stringify(e,Ti,2):String(e),Ti=(e,t)=>ki(t)?Ti(e,t.value):St(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((s,[n,i],o)=>(s[Ms(n,o)+" =>"]=i,s),{})}:zt(t)?{[`Set(${t.size})`]:[...t.values()].map(s=>Ms(s))}:Je(t)?Ms(t):te(t)&&!L(t)&&!yi(t)?String(t):t,Ms=(e,t="")=>{var s;return Je(e)?`Symbol(${(s=e.description)!=null?s:t})`:e};/**
* @vue/reactivity v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/let me;class Fo{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&me&&(me.active?(this.parent=me,this.index=(me.scopes||(me.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,s;if(this.scopes)for(t=0,s=this.scopes.length;t<s;t++)this.scopes[t].pause();for(t=0,s=this.effects.length;t<s;t++)this.effects[t].pause()}}resume(){if(this._active&&this._isPaused){this._isPaused=!1;let t,s;if(this.scopes)for(t=0,s=this.scopes.length;t<s;t++)this.scopes[t].resume();for(t=0,s=this.effects.length;t<s;t++)this.effects[t].resume()}}run(t){if(this._active){const s=me;try{return me=this,t()}finally{me=s}}}on(){++this._on===1&&(this.prevScope=me,me=this)}off(){if(this._on>0&&--this._on===0){if(me===this)me=this.prevScope;else{let t=me;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let s,n;for(s=0,n=this.effects.length;s<n;s++)this.effects[s].stop();for(this.effects.length=0,s=0,n=this.cleanups.length;s<n;s++)this.cleanups[s]();if(this.cleanups.length=0,this.scopes){for(s=0,n=this.scopes.length;s<n;s++)this.scopes[s].stop(!0);this.scopes.length=0}if(!this.detached&&this.parent&&!t){const i=this.parent.scopes.pop();i&&i!==this&&(this.parent.scopes[this.index]=i,i.index=this.index)}this.parent=void 0}}}function Bo(){return me}let oe;const Ls=new WeakSet;class Si{constructor(t){this.fn=t,this.deps=void 0,this.depsTail=void 0,this.flags=5,this.next=void 0,this.cleanup=void 0,this.scheduler=void 0,me&&(me.active?me.effects.push(this):this.flags&=-2)}pause(){this.flags|=64}resume(){this.flags&64&&(this.flags&=-65,Ls.has(this)&&(Ls.delete(this),this.trigger()))}notify(){this.flags&2&&!(this.flags&32)||this.flags&8||Pi(this)}run(){if(!(this.flags&1))return this.fn();this.flags|=2,jn(this),Ci(this);const t=oe,s=Ue;oe=this,Ue=!0;try{return this.fn()}finally{Ai(this),oe=t,Ue=s,this.flags&=-3}}stop(){if(this.flags&1){for(let t=this.deps;t;t=t.nextDep)mn(t);this.deps=this.depsTail=void 0,jn(this),this.onStop&&this.onStop(),this.flags&=-2}}trigger(){this.flags&64?Ls.add(this):this.scheduler?this.scheduler():this.runIfDirty()}runIfDirty(){Js(this)&&this.run()}get dirty(){return Js(this)}}let Ei=0,Ht,Vt;function Pi(e,t=!1){if(e.flags|=8,t){e.next=Vt,Vt=e;return}e.next=Ht,Ht=e}function hn(){Ei++}function gn(){if(--Ei>0)return;if(Vt){let t=Vt;for(Vt=void 0;t;){const s=t.next;t.next=void 0,t.flags&=-9,t=s}}let e;for(;Ht;){let t=Ht;for(Ht=void 0;t;){const s=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(n){e||(e=n)}t=s}}if(e)throw e}function Ci(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function Ai(e){let t,s=e.depsTail,n=s;for(;n;){const i=n.prevDep;n.version===-1?(n===s&&(s=i),mn(n),Ho(n)):t=n,n.dep.activeLink=n.prevActiveLink,n.prevActiveLink=void 0,n=i}e.deps=t,e.depsTail=s}function Js(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&($i(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function $i(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===Zt)||(e.globalVersion=Zt,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Js(e))))return;e.flags|=2;const t=e.dep,s=oe,n=Ue;oe=e,Ue=!0;try{Ci(e);const i=e.fn(e._value);(t.version===0||qe(i,e._value))&&(e.flags|=128,e._value=i,t.version++)}catch(i){throw t.version++,i}finally{oe=s,Ue=n,Ai(e),e.flags&=-3}}function mn(e,t=!1){const{dep:s,prevSub:n,nextSub:i}=e;if(n&&(n.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=n,e.nextSub=void 0),s.subs===e&&(s.subs=n,!n&&s.computed)){s.computed.flags&=-5;for(let o=s.computed.deps;o;o=o.nextDep)mn(o,!0)}!t&&!--s.sc&&s.map&&s.map.delete(s.key)}function Ho(e){const{prevDep:t,nextDep:s}=e;t&&(t.nextDep=s,e.prevDep=void 0),s&&(s.prevDep=t,e.nextDep=void 0)}let Ue=!0;const Oi=[];function Ye(){Oi.push(Ue),Ue=!1}function Xe(){const e=Oi.pop();Ue=e===void 0?!0:e}function jn(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const s=oe;oe=void 0;try{t()}finally{oe=s}}}let Zt=0;class Vo{constructor(t,s){this.sub=t,this.dep=s,this.version=s.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class bn{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!oe||!Ue||oe===this.computed)return;let s=this.activeLink;if(s===void 0||s.sub!==oe)s=this.activeLink=new Vo(oe,this),oe.deps?(s.prevDep=oe.depsTail,oe.depsTail.nextDep=s,oe.depsTail=s):oe.deps=oe.depsTail=s,Di(s);else if(s.version===-1&&(s.version=this.version,s.nextDep)){const n=s.nextDep;n.prevDep=s.prevDep,s.prevDep&&(s.prevDep.nextDep=n),s.prevDep=oe.depsTail,s.nextDep=void 0,oe.depsTail.nextDep=s,oe.depsTail=s,oe.deps===s&&(oe.deps=n)}return s}trigger(t){this.versiLine truncated
* @vue/runtime-core v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/function ss(e,t,s,n){try{return n?e(...n):e()}catch(i){Os(i,t,s)}}function Me(e,t,s,n){if(W(e)){const i=ss(e,t,s,n);return i&&bi(i)&&i.catch(o=>{Os(o,t,s)}),i}if(L(e)){const i=[];for(let o=0;o<e.length;o++)i.push(Me(e[o],t,s,n));return i}}function Os(e,t,s,n=!0){const i=t?t.vnode:null,{errorHandler:o,throwUnhandledErrorInProduction:r}=t&&t.appContext.config||ne;if(t){let a=t.parent;const l=t.proxy,g=`https://vuejs.org/error-reference/#runtime-${s}`;for(;a;){const d=a.ec;if(d){for(let b=0;b<d.length;b++)if(d[b](e,l,g)===!1)return}a=a.parent}if(o){Ye(),ss(o,null,10,[e,l,g]),Xe();return}}gr(e,s,i,n,r)}function gr(e,t,s,n=!0,i=!1){if(i)throw e;console.error(e)}const ke=[];let Ge=-1;const Et=[];let ct=null,kt=0;const Li=Promise.resolve();let bs=null;function Fi(e){const t=bs||Li;return e?t.then(this?e.bind(this):e):t}function mr(e){let t=Ge+1,s=ke.length;for(;t<s;){const n=t+s>>>1,i=ke[n],o=Xt(i);o<e||o===e&&i.flags&2?t=n+1:s=n}return t}function wn(e){if(!(e.flags&1)){const t=Xt(e),s=ke[ke.length-1];!s||!(e.flags&2)&&t>=Xt(s)?ke.push(e):ke.splice(mr(t),0,e),e.flags|=1,Bi()}}function Bi(){bs||(bs=Li.then(Vi))}function br(e){L(e)?Et.push(...e):ct&&e.id===-1?ct.splice(kt+1,0,e):e.flags&1||(Et.push(e),e.flags|=1),Bi()}function Nn(e,t,s=Ge+1){for(;s<ke.length;s++){const n=ke[s];if(n&&n.flags&2){if(e&&n.id!==e.uid)continue;ke.splice(s,1),s--,n.flags&4&&(n.flags&=-2),n(),n.flags&4||(n.flags&=-2)}}}function Hi(e){if(Et.length){const t=[...new Set(Et)].sort((s,n)=>Xt(s)-Xt(n));if(Et.length=0,ct){ct.push(...t);return}for(ct=t,kt=0;kt<ct.length;kt++){const s=ct[kt];s.flags&4&&(s.flags&=-2),s.flags&8||s(),s.flags&=-2}ct=null,kt=0}}const Xt=e=>e.id==null?e.flags&2?-1:1/0:e.id;function Vi(e){try{for(Ge=0;Ge<ke.length;Ge++){const t=ke[Ge];t&&!(t.flags&8)&&(t.flags&4&&(t.flags&=-2),ss(t,t.i,t.i?15:14),t.flags&4||(t.flags&=-2))}}finally{for(;Ge<ke.length;Ge++){const t=ke[Ge];t&&(t.flags&=-2)}Ge=-1,ke.length=0,Hi(),bs=null,(ke.length||Et.length)&&Vi()}}let Re=null,Gi=null;function vs(e){const t=Re;return Re=e,Gi=e&&e.type.__scopeId||null,t}function vr(e,t=Re,s){if(!t||e._n)return e;const n=(...i)=>{n._d&&Zn(-1);const o=vs(t);let r;try{r=e(...i)}finally{vs(o),n._d&&Zn(1)}return r};return n._n=!0,n._c=!0,n._d=!0,n}function pe(e,t){if(Re===null)return e;const s=Is(Re),n=e.dirs||(e.dirs=[]);for(let i=0;i<t.length;i++){let[o,r,a,l=ne]=t[i];o&&(W(o)&&(o={mounted:o,updated:o}),o.deep&&it(r),n.push({dir:o,instance:s,value:r,oldValue:void 0,arg:a,modifiers:l}))}return e}function mt(e,t,s,n){const i=e.dirs,o=t&&t.dirs;for(let r=0;r<i.length;r++){const a=i[r];o&&(a.oldValue=o[r].value);let l=a.dir[n];l&&(Ye(),Me(l,s,8,[e.el,a,e,t]),Xe())}}function yr(e,t){if(Te){let s=Te.provides;const n=Te.parent&&Te.parent.provides;n===s&&(s=Te.provides=Object.create(n)),s[e]=t}}function fs(e,t,s=!1){const n=ma();if(n||Pt){let i=Pt?Pt._context.provides:n?n.parent==null||n.ce?n.vnode.appContext&&n.vnode.appContext.provides:n.parent.provides:void 0;if(i&&e in i)return i[e];if(arguments.length>1)return s&&W(t)?t.call(n&&n.proxy):t}}const _r=Symbol.for("v-scx"),wr=()=>fs(_r);function Hs(e,t,s){return Ki(e,t,s)}function Ki(e,t,s=ne){const{immediate:n,deep:i,flush:o,once:r}=s,a=_e({},s),l=t&&n||!t&&o!=="post";let g;if(es){if(o==="sync"){const A=wr();g=A.__watcherHandles||(A.__watcherHandles=[])}else if(!l){const A=()=>{};return A.stop=Ze,A.resume=Ze,A.pause=Ze,A}}const d=Te;a.call=(A,V,x)=>Me(A,d,V,x);let b=!1;o==="post"?a.scheduler=A=>{Se(A,d&&d.suspense)}:o!=="sync"&&(b=!0,a.scheduler=(A,V)=>{V?A():wn(A)}),a.augmentJob=A=>{t&&(A.flags|=4),b&&(A.flags|=2,d&&(A.id=d.uid,A.i=d))};const E=hr(e,t,a);return es&&(g?g.push(E):l&&E()),E}function xr(e,t,s){const n=this.proxy,i=ue(e)?e.includes(".")?Wi(n,e):()=>n[e]:e.bind(n,n);let o;W(t)?o=t:(o=t.handler,s=t);const r=ns(this),a=Ki(i,o.bind(n),s);return r(),a}function Wi(e,t){const s=t.split(".");return()=>{let n=e;for(let i=0;i<s.length&&n;i++)n=n[s[i]];return n}}const kr=Symbol("_vte"),Tr=e=>e.__isTeleport,Vs=Symbol("_leaveCb");function xn(e,t){e.shapeFlag&6&&e.component?(e.transition=t,xn(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function qi(e){e.ids=[e.ids[0]+e.ids[2]+++"-",0,0]}function Mn(e,t){let s;return!!((s=Object.getOwnPropertyDescriptor(e,t))&&!s.configurable)}const ys=new WeakMap;function Gt(e,t,s,n,i=!1){if(L(e)){e.forEach((x,N)=>Gt(x,t&&(L(t)?t[N]:t),s,n,i));return}if(Kt(n)&&!i){n.shapeFlag&512&&n.type.__asyncResolved&&n.component.subTree.component&&Gt(e,t,s,n.component.subTree);return}const o=n.shapeFlag&4?Is(n.component):n.el,r=i?null:o,{i:a,r:l}=e,g=t&&t.r,d=a.refs===ne?a.refs={}:a.refs,b=a.setupState,E=Y(b),A=b===ne?mi:x=>Mn(d,x)?!1:X(E,x),V=(x,N)=>!(N&&Mn(d,N));if(g!=null&&g!==l){if(Ln(t),ue(g))d[g]=null,A(g)&&(b[g]=null);else if(ye(g)){const x=t;V(g,x.k)&&(g.value=null),x.k&&(d[x.k]=null)}}if(W(l)){Ye();try{ss(l,a,12,[r,d])}finally{Xe()}}else{const x=ue(l),N=ye(l);if(x||N){const R=()=>{if(e.f Line truncated
* @vue/runtime-dom v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/let an;const Xn=typeof window<"u"&&window.trustedTypes;if(Xn)try{an=Xn.createPolicy("vue",{createHTML:e=>e})}catch{}const _o=an?e=>an.createHTML(e):e=>e,ka="http://www.w3.org/2000/svg",Ta="http://www.w3.org/1998/Math/MathML",tt=typeof document<"u"?document:null,Qn=tt&&tt.createElement("template"),Sa={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,n)=>{const i=t==="svg"?tt.createElementNS(ka,e):t==="mathml"?tt.createElementNS(Ta,e):s?tt.createElement(e,{is:s}):tt.createElement(e);return e==="select"&&n&&n.multiple!=null&&i.setAttribute("multiple",n.multiple),i},createText:e=>tt.createTextNode(e),createComment:e=>tt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>tt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,n,i,o){const r=s?s.previousSibling:t.lastChild;if(i&&(i===o||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),s),!(i===o||!(i=i.nextSibling)););else{Qn.innerHTML=_o(n==="svg"?`<svg>${e}</svg>`:n==="mathml"?`<math>${e}</math>`:e);const a=Qn.content;if(n==="svg"||n==="mathml"){const l=a.firstChild;for(;l.firstChild;)a.appendChild(l.firstChild);a.removeChild(l)}t.insertBefore(a,s)}return[r?r.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}},Ea=Symbol("_vtc");function Pa(e,t,s){const n=e[Ea];n&&(t=(t?[t,...n]:[...n]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}const ei=Symbol("_vod"),Ca=Symbol("_vsh"),Aa=Symbol(""),$a=/(?:^|;)\s*display\s*:/;function Oa(e,t,s){const n=e.style,i=ue(s);let o=!1;if(s&&!i){if(t)if(ue(t))for(const r of t.split(";")){const a=r.slice(0,r.indexOf(":")).trim();s[a]==null&&Ft(n,a,"")}else for(const r in t)s[r]==null&&Ft(n,r,"");for(const r in s){r==="display"&&(o=!0);const a=s[r];a!=null?Ra(e,r,!ue(t)&&t?t[r]:void 0,a)||Ft(n,r,a):Ft(n,r,"")}}else if(i){if(t!==s){const r=n[Aa];r&&(s+=";"+r),n.cssText=s,o=$a.test(s)}}else t&&e.removeAttribute("style");ei in e&&(e[ei]=o?n.display:"",e[Ca]&&(n.display="none"))}const ti=/\s*!important$/;function Ft(e,t,s){if(L(s))s.forEach(n=>Ft(e,t,n));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const n=Da(e,t);ti.test(s)?e.setProperty(ft(n),s.replace(ti,""),"important"):e[n]=s}}const si=["Webkit","Moz","ms"],qs={};function Da(e,t){const s=qs[t];if(s)return s;let n=je(t);if(n!=="filter"&&n in e)return qs[t]=n;n=_i(n);for(let i=0;i<si.length;i++){const o=si[i]+n;if(o in e)return qs[t]=o}return t}function Ra(e,t,s,n){return e.tagName==="TEXTAREA"&&(t==="width"||t==="height")&&ue(n)&&s===n}const ni="http://www.w3.org/1999/xlink";function ii(e,t,s,n,i,o=Mo(t)){n&&t.startsWith("xlink:")?s==null?e.removeAttributeNS(ni,t.slice(6,t.length)):e.setAttributeNS(ni,t,s):s==null||o&&!xi(s)?e.removeAttribute(t):e.setAttribute(t,o?"":Je(s)?String(s):s)}function oi(e,t,s,n,i){if(t==="innerHTML"||t==="textContent"){s!=null&&(e[t]=t==="innerHTML"?_o(s):s);return}const o=e.tagName;if(t==="value"&&o!=="PROGRESS"&&!o.includes("-")){const a=o==="OPTION"?e.getAttribute("value")||"":e.value,l=s==null?e.type==="checkbox"?"on":"":String(s);(a!==l||!("_value"in e))&&(e.value=l),s==null&&e.removeAttribute(t),e._value=s;return}let r=!1;if(s===""||s==null){const a=typeof e[t];a==="boolean"?s=xi(s):s==null&&a==="string"?(s="",r=!0):a==="number"&&(s=0,r=!0)}try{e[t]=s}catch{}r&&e.removeAttribute(i||t)}function ot(e,t,s,n){e.addEventListener(t,s,n)}function za(e,t,s,n){e.removeEventListener(t,s,n)}const ri=Symbol("_vei");function Ia(e,t,s,n,i=null){const o=e[ri]||(e[ri]={}),r=o[t];if(n&&r)r.value=n;else{const[a,l]=Na(t);if(n){const g=o[t]=Fa(n,i);ot(e,a,g,l)}else r&&(za(e,a,r,l),o[t]=void 0)}}const ja=/(Once|Passive|Capture)$/,Ua=/^on:?(?:Once|Passive|Capture)$/;function Na(e){let t,s;for(;(s=e.match(ja))&&!Ua.test(e);)t||(t={}),e=e.slice(0,e.length-s[1].length),t[s[1].toLowerCase()]=!0;return[e[2]===":"?e.slice(3):ft(e.slice(2)),t]}let Zs=0;const Ma=Promise.resolve(),La=()=>Zs||(Ma.then(()=>Zs=0),Zs=Date.now());function Fa(e,t){const s=n=>{if(!n._vts)n._vts=Date.now();else if(n._vts<=s.attached)return;const i=s.value;if(L(i)){const o=n.stopImmediatePropagation;n.stopImmediatePropagation=()=>{o.call(n),n._stopped=!0};const r=i.slice(),a=[n];for(let l=0;l<r.length&&!n._stopped;l++){const g=r[l];g&&Me(g,t,5,a)}}else Me(i,t,5,[n])};return s.value=e,s.attached=La(),s}const ai=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Ba=(e,t,s,n,i,o)=>{const r=i==="svg";t==="class"?Pa(e,n,r):t==="style"?Oa(e,s,n):Ss(t)?Es(t)||Ia(e,t,s,n,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Ha(e,t,n,r))?(oi(e,t,n),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&ii(e,t,n,r,o,t!=="value")):e._isVueCE&&(Va(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!ue(n)))?oi(e,je(t),n,o,t):(t==="true-value"?e._trueValue=n:t==="false-value"&&(e._fals Line truncated
@@ -1 +0,0 @@
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--spacing:.25rem;--container-sm:24rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--shadow-xs:var(--shadow-xs);--shadow-sm:var(--shadow-sm);--shadow-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius-control:12px;--radius-card:18px;--radius-pill:999px}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.container{widthLine truncated
-17
View File
@@ -1,17 +0,0 @@
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const o of i)if(o.type==="childList")for(const r of o.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&n(r)}).observe(document,{childList:!0,subtree:!0});function s(i){const o={};return i.integrity&&(o.integrity=i.integrity),i.referrerPolicy&&(o.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?o.credentials="include":i.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function n(i){if(i.ep)return;i.ep=!0;const o=s(i);fetch(i.href,o)}})();/**
* @vue/shared v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/function cn(e){const t=Object.create(null);for(const s of e.split(","))t[s]=1;return s=>s in t}const X={},Tt=[],Je=()=>{},mi=()=>!1,Ss=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&(e.charCodeAt(2)>122||e.charCodeAt(2)<97),Es=e=>e.startsWith("onUpdate:"),ve=Object.assign,un=(e,t)=>{const s=e.indexOf(t);s>-1&&e.splice(s,1)},$o=Object.prototype.hasOwnProperty,W=(e,t)=>$o.call(e,t),M=Array.isArray,St=e=>ss(e)==="[object Map]",Dt=e=>ss(e)==="[object Set]",Dn=e=>ss(e)==="[object Date]",V=e=>typeof e=="function",oe=e=>typeof e=="string",Ye=e=>typeof e=="symbol",Z=e=>e!==null&&typeof e=="object",bi=e=>(Z(e)||V(e))&&V(e.then)&&V(e.catch),vi=Object.prototype.toString,ss=e=>vi.call(e),Oo=e=>ss(e).slice(8,-1),yi=e=>ss(e)==="[object Object]",dn=e=>oe(e)&&e!=="NaN"&&e[0]!=="-"&&""+parseInt(e,10)===e,Ht=cn(",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted"),Ps=e=>{const t=Object.create(null);return(s=>t[s]||(t[s]=e(s)))},Ro=/-\w/g,De=Ps(e=>e.replace(Ro,t=>t.slice(1).toUpperCase())),zo=/\B([A-Z])/g,ht=Ps(e=>e.replace(zo,"-$1").toLowerCase()),_i=Ps(e=>e.charAt(0).toUpperCase()+e.slice(1)),Ns=Ps(e=>e?`on${_i(e)}`:""),Ze=(e,t)=>!Object.is(e,t),ps=(e,...t)=>{for(let s=0;s<e.length;s++)e[s](...t)},wi=(e,t,s,n=!1)=>{Object.defineProperty(e,t,{configurable:!0,enumerable:!1,writable:n,value:s})},Cs=e=>{const t=parseFloat(e);return isNaN(t)?e:t};let In;const As=()=>In||(In=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:{});function pn(e){if(M(e)){const t={};for(let s=0;s<e.length;s++){const n=e[s],i=oe(n)?Uo(n):pn(n);if(i)for(const o in i)t[o]=i[o]}return t}else if(oe(e)||Z(e))return e}const Do=/;(?![^(]*\))/g,Io=/:([^]+)/,jo=/\/\*[^]*?\*\//g;function Uo(e){const t={};return e.replace(jo,"").split(Do).forEach(s=>{if(s){const n=s.split(Io);n.length>1&&(t[n[0].trim()]=n[1].trim())}}),t}function Ue(e){let t="";if(oe(e))t=e;else if(M(e))for(let s=0;s<e.length;s++){const n=Ue(e[s]);n&&(t+=n+" ")}else if(Z(e))for(const s in e)e[s]&&(t+=s+" ");return t.trim()}const No="itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly",Mo=cn(No);function xi(e){return!!e||e===""}function Lo(e,t){if(e.length!==t.length)return!1;let s=!0;for(let n=0;s&&n<e.length;n++)s=dt(e[n],t[n]);return s}function dt(e,t){if(e===t)return!0;let s=Dn(e),n=Dn(t);if(s||n)return s&&n?e.getTime()===t.getTime():!1;if(s=Ye(e),n=Ye(t),s||n)return e===t;if(s=M(e),n=M(t),s||n)return s&&n?Lo(e,t):!1;if(s=Z(e),n=Z(t),s||n){if(!s||!n)return!1;const i=Object.keys(e).length,o=Object.keys(t).length;if(i!==o)return!1;for(const r in e){const a=e.hasOwnProperty(r),l=t.hasOwnProperty(r);if(a&&!l||!a&&l||!dt(e[r],t[r]))return!1}}return String(e)===String(t)}function fn(e,t){return e.findIndex(s=>dt(s,t))}const ki=e=>!!(e&&e.__v_isRef===!0),m=e=>oe(e)?e:e==null?"":M(e)||Z(e)&&(e.toString===vi||!V(e.toString))?ki(e)?m(e.value):JSON.stringify(e,Ti,2):String(e),Ti=(e,t)=>ki(t)?Ti(e,t.value):St(t)?{[`Map(${t.size})`]:[...t.entries()].reduce((s,[n,i],o)=>(s[Ms(n,o)+" =>"]=i,s),{})}:Dt(t)?{[`Set(${t.size})`]:[...t.values()].map(s=>Ms(s))}:Ye(t)?Ms(t):Z(t)&&!M(t)&&!yi(t)?String(t):t,Ms=(e,t="")=>{var s;return Ye(e)?`Symbol(${(s=e.description)!=null?s:t})`:e};/**
* @vue/reactivity v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/let he;class Fo{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&he&&(he.active?(this.parent=he,this.index=(he.scopes||(he.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,s;if(this.scopes)for(t=0,s=this.scopes.length;t<s;t++)this.scopes[t].pause();for(t=0,s=this.effects.length;t<s;t++)this.effects[t].pause()}}resume(){if(this._active&&this._isPaused){this._isPaused=!1;let t,s;if(this.scopes)for(t=0,s=this.scopes.length;t<s;t++)this.scopes[t].resume();for(t=0,s=this.effects.length;t<s;t++)this.effects[t].resume()}}run(t){if(this._active){const s=he;try{return he=this,t()}finally{he=s}}}on(){++this._on===1&&(this.prevScope=he,he=this)}off(){if(this._on>0&&--this._on===0){if(he===this)he=this.prevScope;else{let t=he;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let s,n;for(s=0,n=this.effects.length;s<n;s++)this.effects[s].stop();for(this.effects.length=0,s=0,n=this.cleanups.length;s<n;s++)this.cleanups[s]();if(this.cleanups.length=0,this.scopes){for(s=0,n=this.scopes.length;s<n;s++)this.scopes[s].stop(!0);this.scopes.length=0}if(!this.detached&&this.parent&&!t){const i=this.parent.scopes.pop();i&&i!==this&&(this.parent.scopes[this.index]=i,i.index=this.index)}this.parent=void 0}}}function Bo(){return he}let ee;const Ls=new WeakSet;class Si{constructor(t){this.fn=t,this.deps=void 0,this.depsTail=void 0,this.flags=5,this.next=void 0,this.cleanup=void 0,this.scheduler=void 0,he&&(he.active?he.effects.push(this):this.flags&=-2)}pause(){this.flags|=64}resume(){this.flags&64&&(this.flags&=-65,Ls.has(this)&&(Ls.delete(this),this.trigger()))}notify(){this.flags&2&&!(this.flags&32)||this.flags&8||Pi(this)}run(){if(!(this.flags&1))return this.fn();this.flags|=2,jn(this),Ci(this);const t=ee,s=Ie;ee=this,Ie=!0;try{return this.fn()}finally{Ai(this),ee=t,Ie=s,this.flags&=-3}}stop(){if(this.flags&1){for(let t=this.deps;t;t=t.nextDep)mn(t);this.deps=this.depsTail=void 0,jn(this),this.onStop&&this.onStop(),this.flags&=-2}}trigger(){this.flags&64?Ls.add(this):this.scheduler?this.scheduler():this.runIfDirty()}runIfDirty(){Js(this)&&this.run()}get dirty(){return Js(this)}}let Ei=0,Vt,Gt;function Pi(e,t=!1){if(e.flags|=8,t){e.next=Gt,Gt=e;return}e.next=Vt,Vt=e}function hn(){Ei++}function gn(){if(--Ei>0)return;if(Gt){let t=Gt;for(Gt=void 0;t;){const s=t.next;t.next=void 0,t.flags&=-9,t=s}}let e;for(;Vt;){let t=Vt;for(Vt=void 0;t;){const s=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(n){e||(e=n)}t=s}}if(e)throw e}function Ci(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function Ai(e){let t,s=e.depsTail,n=s;for(;n;){const i=n.prevDep;n.version===-1?(n===s&&(s=i),mn(n),Ho(n)):t=n,n.dep.activeLink=n.prevActiveLink,n.prevActiveLink=void 0,n=i}e.deps=t,e.depsTail=s}function Js(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&($i(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function $i(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===Jt)||(e.globalVersion=Jt,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Js(e))))return;e.flags|=2;const t=e.dep,s=ee,n=Ie;ee=e,Ie=!0;try{Ci(e);const i=e.fn(e._value);(t.version===0||Ze(i,e._value))&&(e.flags|=128,e._value=i,t.version++)}catch(i){throw t.version++,i}finally{ee=s,Ie=n,Ai(e),e.flags&=-3}}function mn(e,t=!1){const{dep:s,prevSub:n,nextSub:i}=e;if(n&&(n.nextSub=i,e.prevSub=void 0),i&&(i.prevSub=n,e.nextSub=void 0),s.subs===e&&(s.subs=n,!n&&s.computed)){s.computed.flags&=-5;for(let o=s.computed.deps;o;o=o.nextDep)mn(o,!0)}!t&&!--s.sc&&s.map&&s.map.delete(s.key)}function Ho(e){const{prevDep:t,nextDep:s}=e;t&&(t.nextDep=s,e.prevDep=void 0),s&&(s.prevDep=t,e.nextDep=void 0)}let Ie=!0;const Oi=[];function Xe(){Oi.push(Ie),Ie=!1}function Qe(){const e=Oi.pop();Ie=e===void 0?!0:e}function jn(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const s=ee;ee=void 0;try{t()}finally{ee=s}}}let Jt=0;class Vo{constructor(t,s){this.sub=t,this.dep=s,this.version=s.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class bn{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!ee||!Ie||ee===this.computed)return;let s=this.activeLink;if(s===void 0||s.sub!==ee)s=this.activeLink=new Vo(ee,this),ee.deps?(s.prevDep=ee.depsTail,ee.depsTail.nextDep=s,ee.depsTail=s):ee.deps=ee.depsTail=s,Ri(s);else if(s.version===-1&&(s.version=this.version,s.nextDep)){const n=s.nextDep;n.prevDep=s.prevDep,s.prevDep&&(s.prevDep.nextDep=n),s.prevDep=ee.depsTail,s.nextDep=void 0,ee.depsTail.nextDep=s,ee.depsTail=s,ee.deps===s&&(ee.deps=n)}return s}trigger(t){this.versiLine truncated
* @vue/runtime-core v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/function ns(e,t,s,n){try{return n?e(...n):e()}catch(i){Os(i,t,s)}}function Me(e,t,s,n){if(V(e)){const i=ns(e,t,s,n);return i&&bi(i)&&i.catch(o=>{Os(o,t,s)}),i}if(M(e)){const i=[];for(let o=0;o<e.length;o++)i.push(Me(e[o],t,s,n));return i}}function Os(e,t,s,n=!0){const i=t?t.vnode:null,{errorHandler:o,throwUnhandledErrorInProduction:r}=t&&t.appContext.config||X;if(t){let a=t.parent;const l=t.proxy,g=`https://vuejs.org/error-reference/#runtime-${s}`;for(;a;){const d=a.ec;if(d){for(let b=0;b<d.length;b++)if(d[b](e,l,g)===!1)return}a=a.parent}if(o){Xe(),ns(o,null,10,[e,l,g]),Qe();return}}gr(e,s,i,n,r)}function gr(e,t,s,n=!0,i=!1){if(i)throw e;console.error(e)}const we=[];let Ke=-1;const Et=[];let ut=null,kt=0;const Li=Promise.resolve();let bs=null;function Fi(e){const t=bs||Li;return e?t.then(this?e.bind(this):e):t}function mr(e){let t=Ke+1,s=we.length;for(;t<s;){const n=t+s>>>1,i=we[n],o=Qt(i);o<e||o===e&&i.flags&2?t=n+1:s=n}return t}function wn(e){if(!(e.flags&1)){const t=Qt(e),s=we[we.length-1];!s||!(e.flags&2)&&t>=Qt(s)?we.push(e):we.splice(mr(t),0,e),e.flags|=1,Bi()}}function Bi(){bs||(bs=Li.then(Vi))}function br(e){M(e)?Et.push(...e):ut&&e.id===-1?ut.splice(kt+1,0,e):e.flags&1||(Et.push(e),e.flags|=1),Bi()}function Nn(e,t,s=Ke+1){for(;s<we.length;s++){const n=we[s];if(n&&n.flags&2){if(e&&n.id!==e.uid)continue;we.splice(s,1),s--,n.flags&4&&(n.flags&=-2),n(),n.flags&4||(n.flags&=-2)}}}function Hi(e){if(Et.length){const t=[...new Set(Et)].sort((s,n)=>Qt(s)-Qt(n));if(Et.length=0,ut){ut.push(...t);return}for(ut=t,kt=0;kt<ut.length;kt++){const s=ut[kt];s.flags&4&&(s.flags&=-2),s.flags&8||s(),s.flags&=-2}ut=null,kt=0}}const Qt=e=>e.id==null?e.flags&2?-1:1/0:e.id;function Vi(e){try{for(Ke=0;Ke<we.length;Ke++){const t=we[Ke];t&&!(t.flags&8)&&(t.flags&4&&(t.flags&=-2),ns(t,t.i,t.i?15:14),t.flags&4||(t.flags&=-2))}}finally{for(;Ke<we.length;Ke++){const t=we[Ke];t&&(t.flags&=-2)}Ke=-1,we.length=0,Hi(),bs=null,(we.length||Et.length)&&Vi()}}let Ae=null,Gi=null;function vs(e){const t=Ae;return Ae=e,Gi=e&&e.type.__scopeId||null,t}function vr(e,t=Ae,s){if(!t||e._n)return e;const n=(...i)=>{n._d&&Zn(-1);const o=vs(t);let r;try{r=e(...i)}finally{vs(o),n._d&&Zn(1)}return r};return n._n=!0,n._c=!0,n._d=!0,n}function le(e,t){if(Ae===null)return e;const s=Is(Ae),n=e.dirs||(e.dirs=[]);for(let i=0;i<t.length;i++){let[o,r,a,l=X]=t[i];o&&(V(o)&&(o={mounted:o,updated:o}),o.deep&&ot(r),n.push({dir:o,instance:s,value:r,oldValue:void 0,arg:a,modifiers:l}))}return e}function bt(e,t,s,n){const i=e.dirs,o=t&&t.dirs;for(let r=0;r<i.length;r++){const a=i[r];o&&(a.oldValue=o[r].value);let l=a.dir[n];l&&(Xe(),Me(l,s,8,[e.el,a,e,t]),Qe())}}function yr(e,t){if(xe){let s=xe.provides;const n=xe.parent&&xe.parent.provides;n===s&&(s=xe.provides=Object.create(n)),s[e]=t}}function fs(e,t,s=!1){const n=ma();if(n||Pt){let i=Pt?Pt._context.provides:n?n.parent==null||n.ce?n.vnode.appContext&&n.vnode.appContext.provides:n.parent.provides:void 0;if(i&&e in i)return i[e];if(arguments.length>1)return s&&V(t)?t.call(n&&n.proxy):t}}const _r=Symbol.for("v-scx"),wr=()=>fs(_r);function Hs(e,t,s){return Ki(e,t,s)}function Ki(e,t,s=X){const{immediate:n,deep:i,flush:o,once:r}=s,a=ve({},s),l=t&&n||!t&&o!=="post";let g;if(ts){if(o==="sync"){const $=wr();g=$.__watcherHandles||($.__watcherHandles=[])}else if(!l){const $=()=>{};return $.stop=Je,$.resume=Je,$.pause=Je,$}}const d=xe;a.call=($,F,k)=>Me($,d,F,k);let b=!1;o==="post"?a.scheduler=$=>{ke($,d&&d.suspense)}:o!=="sync"&&(b=!0,a.scheduler=($,F)=>{F?$():wn($)}),a.augmentJob=$=>{t&&($.flags|=4),b&&($.flags|=2,d&&($.id=d.uid,$.i=d))};const P=hr(e,t,a);return ts&&(g?g.push(P):l&&P()),P}function xr(e,t,s){const n=this.proxy,i=oe(e)?e.includes(".")?Wi(n,e):()=>n[e]:e.bind(n,n);let o;V(t)?o=t:(o=t.handler,s=t);const r=is(this),a=Ki(i,o.bind(n),s);return r(),a}function Wi(e,t){const s=t.split(".");return()=>{let n=e;for(let i=0;i<s.length&&n;i++)n=n[s[i]];return n}}const kr=Symbol("_vte"),Tr=e=>e.__isTeleport,Vs=Symbol("_leaveCb");function xn(e,t){e.shapeFlag&6&&e.component?(e.transition=t,xn(e.component.subTree,t)):e.shapeFlag&128?(e.ssContent.transition=t.clone(e.ssContent),e.ssFallback.transition=t.clone(e.ssFallback)):e.transition=t}function qi(e){e.ids=[e.ids[0]+e.ids[2]+++"-",0,0]}function Mn(e,t){let s;return!!((s=Object.getOwnPropertyDescriptor(e,t))&&!s.configurable)}const ys=new WeakMap;function Kt(e,t,s,n,i=!1){if(M(e)){e.forEach((k,O)=>Kt(k,t&&(M(t)?t[O]:t),s,n,i));return}if(Wt(n)&&!i){n.shapeFlag&512&&n.type.__asyncResolved&&n.component.subTree.component&&Kt(e,t,s,n.component.subTree);return}const o=n.shapeFlag&4?Is(n.component):n.el,r=i?null:o,{i:a,r:l}=e,g=t&&t.r,d=a.refs===X?a.refs={}:a.refs,b=a.setupState,P=K(b),$=b===X?mi:k=>Mn(d,k)?!1:W(P,k),F=(k,O)=>!(O&&Mn(d,O));if(g!=null&&g!==l){if(Ln(t),oe(g))d[g]=null,$(g)&&(b[g]=null);else if(be(g)){const k=t;F(g,k.k)&&(g.value=null),k.k&&(d[k.k]=null)}}if(V(l)){Xe();try{ns(l,a,12,[r,d])}finally{Qe()}}else{const k=oe(l),O=be(l);if(k||O){const E=()=>{if(e.f){con Line truncated
* @vue/runtime-dom v3.5.39
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
**/let an;const Xn=typeof window<"u"&&window.trustedTypes;if(Xn)try{an=Xn.createPolicy("vue",{createHTML:e=>e})}catch{}const _o=an?e=>an.createHTML(e):e=>e,ka="http://www.w3.org/2000/svg",Ta="http://www.w3.org/1998/Math/MathML",st=typeof document<"u"?document:null,Qn=st&&st.createElement("template"),Sa={insert:(e,t,s)=>{t.insertBefore(e,s||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,s,n)=>{const i=t==="svg"?st.createElementNS(ka,e):t==="mathml"?st.createElementNS(Ta,e):s?st.createElement(e,{is:s}):st.createElement(e);return e==="select"&&n&&n.multiple!=null&&i.setAttribute("multiple",n.multiple),i},createText:e=>st.createTextNode(e),createComment:e=>st.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>st.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,s,n,i,o){const r=s?s.previousSibling:t.lastChild;if(i&&(i===o||i.nextSibling))for(;t.insertBefore(i.cloneNode(!0),s),!(i===o||!(i=i.nextSibling)););else{Qn.innerHTML=_o(n==="svg"?`<svg>${e}</svg>`:n==="mathml"?`<math>${e}</math>`:e);const a=Qn.content;if(n==="svg"||n==="mathml"){const l=a.firstChild;for(;l.firstChild;)a.appendChild(l.firstChild);a.removeChild(l)}t.insertBefore(a,s)}return[r?r.nextSibling:t.firstChild,s?s.previousSibling:t.lastChild]}},Ea=Symbol("_vtc");function Pa(e,t,s){const n=e[Ea];n&&(t=(t?[t,...n]:[...n]).join(" ")),t==null?e.removeAttribute("class"):s?e.setAttribute("class",t):e.className=t}const ei=Symbol("_vod"),Ca=Symbol("_vsh"),Aa=Symbol(""),$a=/(?:^|;)\s*display\s*:/;function Oa(e,t,s){const n=e.style,i=oe(s);let o=!1;if(s&&!i){if(t)if(oe(t))for(const r of t.split(";")){const a=r.slice(0,r.indexOf(":")).trim();s[a]==null&&Bt(n,a,"")}else for(const r in t)s[r]==null&&Bt(n,r,"");for(const r in s){r==="display"&&(o=!0);const a=s[r];a!=null?za(e,r,!oe(t)&&t?t[r]:void 0,a)||Bt(n,r,a):Bt(n,r,"")}}else if(i){if(t!==s){const r=n[Aa];r&&(s+=";"+r),n.cssText=s,o=$a.test(s)}}else t&&e.removeAttribute("style");ei in e&&(e[ei]=o?n.display:"",e[Ca]&&(n.display="none"))}const ti=/\s*!important$/;function Bt(e,t,s){if(M(s))s.forEach(n=>Bt(e,t,n));else if(s==null&&(s=""),t.startsWith("--"))e.setProperty(t,s);else{const n=Ra(e,t);ti.test(s)?e.setProperty(ht(n),s.replace(ti,""),"important"):e[n]=s}}const si=["Webkit","Moz","ms"],qs={};function Ra(e,t){const s=qs[t];if(s)return s;let n=De(t);if(n!=="filter"&&n in e)return qs[t]=n;n=_i(n);for(let i=0;i<si.length;i++){const o=si[i]+n;if(o in e)return qs[t]=o}return t}function za(e,t,s,n){return e.tagName==="TEXTAREA"&&(t==="width"||t==="height")&&oe(n)&&s===n}const ni="http://www.w3.org/1999/xlink";function ii(e,t,s,n,i,o=Mo(t)){n&&t.startsWith("xlink:")?s==null?e.removeAttributeNS(ni,t.slice(6,t.length)):e.setAttributeNS(ni,t,s):s==null||o&&!xi(s)?e.removeAttribute(t):e.setAttribute(t,o?"":Ye(s)?String(s):s)}function oi(e,t,s,n,i){if(t==="innerHTML"||t==="textContent"){s!=null&&(e[t]=t==="innerHTML"?_o(s):s);return}const o=e.tagName;if(t==="value"&&o!=="PROGRESS"&&!o.includes("-")){const a=o==="OPTION"?e.getAttribute("value")||"":e.value,l=s==null?e.type==="checkbox"?"on":"":String(s);(a!==l||!("_value"in e))&&(e.value=l),s==null&&e.removeAttribute(t),e._value=s;return}let r=!1;if(s===""||s==null){const a=typeof e[t];a==="boolean"?s=xi(s):s==null&&a==="string"?(s="",r=!0):a==="number"&&(s=0,r=!0)}try{e[t]=s}catch{}r&&e.removeAttribute(i||t)}function rt(e,t,s,n){e.addEventListener(t,s,n)}function Da(e,t,s,n){e.removeEventListener(t,s,n)}const ri=Symbol("_vei");function Ia(e,t,s,n,i=null){const o=e[ri]||(e[ri]={}),r=o[t];if(n&&r)r.value=n;else{const[a,l]=Na(t);if(n){const g=o[t]=Fa(n,i);rt(e,a,g,l)}else r&&(Da(e,a,r,l),o[t]=void 0)}}const ja=/(Once|Passive|Capture)$/,Ua=/^on:?(?:Once|Passive|Capture)$/;function Na(e){let t,s;for(;(s=e.match(ja))&&!Ua.test(e);)t||(t={}),e=e.slice(0,e.length-s[1].length),t[s[1].toLowerCase()]=!0;return[e[2]===":"?e.slice(3):ht(e.slice(2)),t]}let Zs=0;const Ma=Promise.resolve(),La=()=>Zs||(Ma.then(()=>Zs=0),Zs=Date.now());function Fa(e,t){const s=n=>{if(!n._vts)n._vts=Date.now();else if(n._vts<=s.attached)return;const i=s.value;if(M(i)){const o=n.stopImmediatePropagation;n.stopImmediatePropagation=()=>{o.call(n),n._stopped=!0};const r=i.slice(),a=[n];for(let l=0;l<r.length&&!n._stopped;l++){const g=r[l];g&&Me(g,t,5,a)}}else Me(i,t,5,[n])};return s.value=e,s.attached=La(),s}const ai=e=>e.charCodeAt(0)===111&&e.charCodeAt(1)===110&&e.charCodeAt(2)>96&&e.charCodeAt(2)<123,Ba=(e,t,s,n,i,o)=>{const r=i==="svg";t==="class"?Pa(e,n,r):t==="style"?Oa(e,s,n):Ss(t)?Es(t)||Ia(e,t,s,n,o):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):Ha(e,t,n,r))?(oi(e,t,n),!e.tagName.includes("-")&&(t==="value"||t==="checked"||t==="selected")&&ii(e,t,n,r,o,t!=="value")):e._isVueCE&&(Va(e,t)||e._def.__asyncLoader&&(/[A-Z]/.test(t)||!oe(n)))?oi(e,De(t),n,o,t):(t==="true-value"?e._trueValue=n:t==="false-value"&&(e._fals Line truncated
@@ -0,0 +1 @@
/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial}}}@layer theme{:root,:host{--font-sans:var(--font-sans);--font-mono:var(--font-mono);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--shadow-xs:var(--shadow-xs);--shadow-sm:var(--shadow-sm);--shadow-md:0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--radius-control:12px;--radius-card:18px;--radius-pill:999px}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.sr-only{clip-path:inset(50%);white-space:nowrap;bordLine truncated
+2 -2
View File
@@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#2563eb" />
<title>DriverVault · API Server</title>
<script type="module" crossorigin src="/assets/index-DYiq470x.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CGuUVjJH.css">
<script type="module" crossorigin src="/assets/index-BjBOfjar.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-nQWOOvsA.css">
</head>
<body>
<div id="app"></div>
@@ -171,7 +171,7 @@ func (p *Plugin) Descriptor() plugins.Descriptor {
Provider: "Anker Solix (V1 Smart EV Charger)",
Version: "0.2.0",
Kind: plugins.KindBuiltin,
Category: plugins.CategoryAPIsExternal,
Category: plugins.CategoryChargers,
AuthType: plugins.AuthBasic,
Capabilities: []plugins.Capability{
{ID: "chargers", Method: "POST", Endpoint: epStandaloneChargers, Description: "List EV chargers bound to the account."},
@@ -169,7 +169,7 @@ func (p *Plugin) Descriptor() plugins.Descriptor {
Provider: "Greencell (HabuDen EV charger)",
Version: "1.0.0",
Kind: plugins.KindBuiltin,
Category: plugins.CategoryAPIsExternal,
Category: plugins.CategoryChargers,
AuthType: plugins.AuthBasic,
Capabilities: []plugins.Capability{
{ID: "chargers", Method: "SUB", Endpoint: discoveryTopic,
@@ -124,7 +124,7 @@ func (p *Plugin) Descriptor() plugins.Descriptor {
Provider: "Toyota Connected Europe",
Version: "0.2.0",
Kind: plugins.KindBuiltin,
Category: plugins.CategoryAPIsExternal,
Category: plugins.CategoryVehicles,
AuthType: plugins.AuthOAuth2,
Capabilities: []plugins.Capability{
{ID: "vehicles", Method: "GET", Endpoint: epVehicleGUID, Description: "List vehicles registered to the account."},
+3 -1
View File
@@ -90,8 +90,10 @@ func (c *Capability) UnmarshalJSON(b []byte) error {
}
// Category groups a plugin under a tab in the admin panel. A plugin with an
// empty category is treated as CategoryAPIsExternal by the panel.
// empty or unrecognised category is treated as CategoryAPIsExternal by the panel.
const (
CategoryVehicles = "vehicles" // car manufacturers' connected-car services
CategoryChargers = "chargers" // EV chargers and charging hardware
CategoryAPIsExternal = "apis-external" // remote HTTP APIs (external plugins)
CategoryDrivesExternal = "drives-external" // remote file stores (FTP/SFTP)
CategoryDrivesLocal = "drives-local" // drives on the host machine
+3 -19
View File
@@ -3,6 +3,7 @@ import { ref, computed, onMounted } from "vue";
import { theme, toggleTheme } from "./theme";
import { t, lang, setLang, TRANSLATED_LANGUAGES } from "./i18n";
import { me, token, restore, logout, isManager, isSuperadmin } from "./api";
import Logo from "./components/Logo.vue";
import LoginView from "./components/LoginView.vue";
import StatusCard from "./components/StatusCard.vue";
import PocketBaseCard from "./components/PocketBaseCard.vue";
@@ -67,13 +68,6 @@ function signOut() {
section.value = "overview";
}
// Logo bar fills — flip for legibility on the dark shell.
const barFills = computed(() =>
theme.value === "dark"
? ["#60a5fa", "#93c5fd", "#ffffff"]
: ["var(--brand-700)", "var(--brand-500)", "var(--brand-400)"],
);
// The DriverVault REST surface, grouped by resource. Mirrors the routes
// registered in internal/api/server.go.
const publicApi = [
@@ -270,18 +264,8 @@ const superadminApi = [
<div class="mx-auto flex max-w-4xl flex-col gap-6 px-6 pt-12 pb-16">
<!-- Header -->
<div class="flex items-center gap-3">
<span class="inline-flex items-center gap-2.5 select-none">
<svg class="h-8 w-8 shrink-0" viewBox="0 0 48 48" fill="none" aria-hidden="true">
<g transform="translate(7 0) skewX(-13)">
<rect x="9" y="16" width="6" height="16" rx="3" :fill="barFills[0]" />
<rect x="19" y="12" width="6" height="24" rx="3" :fill="barFills[1]" />
<rect x="29" y="8" width="6" height="32" rx="3" :fill="barFills[2]" />
</g>
</svg>
<span class="text-2xl leading-none font-extrabold tracking-[-0.03em] italic">
<span class="text-strong">Driver</span><span class="text-brandtext">Vault</span>
</span>
</span>
<!-- The shared DriverVault lockup, on-dark on the dark shell. -->
<Logo :on-dark="theme === 'dark'" class="h-7" />
<span class="eyebrow mt-1.5">{{ t("app.apiServer") }}</span>
<div class="flex-1"></div>
+30
View File
@@ -0,0 +1,30 @@
<script setup>
// DriverVault lockup: the tri-bar "Fast Forward" mark + Archivo italic-800 wordmark.
// Kept identical to the Web App's Logo.vue — the same mark has to render the same
// way in both consoles. Colours come from the design tokens so it reads on both
// light and dark shells; `onDark` forces the light-on-dark variant (white bars/
// "Driver", brand-400 "Vault"), which this panel selects from the theme toggle.
defineProps({
iconOnly: { type: Boolean, default: false },
onDark: { type: Boolean, default: false },
});
</script>
<template>
<span class="inline-flex items-center gap-2.5 select-none">
<svg class="h-full w-auto shrink-0" viewBox="0 0 48 48" fill="none" aria-hidden="true">
<g transform="translate(7 0) skewX(-13)">
<rect x="9" y="16" width="6" height="16" rx="3" :fill="onDark ? '#60A5FA' : 'var(--brand-700)'" />
<rect x="19" y="12" width="6" height="24" rx="3" :fill="onDark ? '#93C5FD' : 'var(--brand-500)'" />
<rect x="29" y="8" width="6" height="32" rx="3" :fill="onDark ? '#ffffff' : 'var(--brand-400)'" />
</g>
</svg>
<span
v-if="!iconOnly"
class="text-[1.35em] font-extrabold italic leading-none tracking-[-0.03em]"
>
<span :class="onDark ? 'text-white' : 'text-strong'">Driver</span><span :class="onDark ? 'text-brand-400' : 'text-brandtext'">Vault</span>
</span>
<span class="sr-only">DriverVault</span>
</span>
</template>
@@ -1,5 +1,5 @@
<script setup>
import { ref, onMounted, reactive } from "vue";
import { ref, computed, onMounted, reactive } from "vue";
import { request } from "../api";
import { t } from "../i18n";
@@ -14,6 +14,30 @@ const drafts = reactive({}); // name -> { key: value }
const rowNotice = reactive({}); // name -> string
const showRegister = ref(false);
const reg = ref({ name: "", baseURL: "", provider: "" });
const tab = ref(""); // selected category tab; empty falls back to the first one
// Tab order, mirroring the Category* constants in internal/plugins/plugin.go. A
// plugin whose category is empty or unknown to this panel lands under the
// external-APIs tab rather than disappearing.
const CATEGORIES = ["vehicles", "chargers", "apis-external", "drives-external", "drives-local"];
const categoryOf = (p) => (CATEGORIES.includes(p.category) ? p.category : "apis-external");
// Only categories that actually have a plugin get a tab — a fresh install with
// two builtins shows two tabs, not five empty ones.
const groups = computed(() => {
const by = {};
for (const p of plugins.value) (by[categoryOf(p)] ||= []).push(p);
return CATEGORIES.filter((c) => by[c]).map((c) => ({
id: c,
label: t(`plugins.categories.${c}`),
plugins: by[c],
}));
});
// Falling back to the first group keeps the card populated when the selected
// tab's last plugin is removed (or a reload drops it).
const activeGroup = computed(() => groups.value.find((g) => g.id === tab.value) || groups.value[0]);
const shown = computed(() => activeGroup.value?.plugins || []);
async function load() {
try {
@@ -153,7 +177,21 @@ const healthClass = (s) =>
{{ t("plugins.empty") }}
</p>
<div v-for="p in plugins" :key="p.name" class="border-t border-subtle first:border-t-0">
<!-- Category tabs: car manufacturers, EV chargers, everything else. -->
<nav v-if="groups.length > 1" class="flex flex-wrap gap-1.5 border-b border-subtle px-5 py-3">
<button
v-for="g in groups"
:key="g.id"
class="dh-btn-ghost"
:class="activeGroup?.id === g.id ? 'border-accent text-brandtext' : ''"
@click="tab = g.id"
>
{{ g.label }}
<span class="dh-pill bg-sunken text-muted">{{ g.plugins.length }}</span>
</button>
</nav>
<div v-for="p in shown" :key="p.name" class="border-t border-subtle first:border-t-0">
<!-- Summary row -->
<div class="flex items-center gap-3 px-5 py-3">
<button class="flex flex-1 items-center gap-3 text-left" @click="expand(p)">
+7
View File
@@ -134,6 +134,13 @@
"plugins": {
"title": "Plugins",
"subtitle": "Integrationer med tredjepartstjenester",
"categories": {
"vehicles": "Bilproducenter",
"chargers": "EV-ladere",
"apis-external": "Øvrige API'er",
"drives-external": "Eksterne drev",
"drives-local": "Lokale drev"
},
"registerExternal": "Registrér ekstern",
"cancelRegister": "Annuller",
"name": "Navn",
+7
View File
@@ -134,6 +134,13 @@
"plugins": {
"title": "Plugins",
"subtitle": "Third-party service integrations",
"categories": {
"vehicles": "Car manufacturers",
"chargers": "EV chargers",
"apis-external": "Other APIs",
"drives-external": "Remote drives",
"drives-local": "Local drives"
},
"registerExternal": "Register external",
"cancelRegister": "Cancel",
"name": "Name",
+7
View File
@@ -134,6 +134,13 @@
"plugins": {
"title": "Wtyczki",
"subtitle": "Integracje z usługami zewnętrznymi",
"categories": {
"vehicles": "Producenci samochodów",
"chargers": "Ładowarki EV",
"apis-external": "Pozostałe API",
"drives-external": "Dyski zdalne",
"drives-local": "Dyski lokalne"
},
"registerExternal": "Zarejestruj zewnętrzną",
"cancelRegister": "Anuluj",
"name": "Nazwa",