gitroll 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/SECURITY.md +59 -0
- package/SPEC.md +144 -0
- package/dist/THIRD_PARTY_NOTICES.txt +19 -0
- package/dist/gitroll.mjs +11148 -0
- package/dist/web/THIRD_PARTY_NOTICES.txt +19 -0
- package/dist/web/app.js +118 -0
- package/dist/web/icon.svg +1 -0
- package/dist/web/index.html +67 -0
- package/dist/web/style.css +224 -0
- package/package.json +57 -0
- package/template/.gitattributes +3 -0
- package/template/.gitroll/config.yaml +2 -0
- package/template/.gitroll/types/.gitkeep +0 -0
- package/template/README.md +13 -0
- package/template/attachments/.gitkeep +0 -0
- package/template/entries/.gitkeep +0 -0
- package/template/projects/.gitkeep +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
GitRoll includes the following third-party software.
|
|
2
|
+
|
|
3
|
+
========================================================================
|
|
4
|
+
yaml 2.9.1 (ISC)
|
|
5
|
+
========================================================================
|
|
6
|
+
|
|
7
|
+
Copyright Eemeli Aro <eemeli@gmail.com>
|
|
8
|
+
|
|
9
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
10
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
11
|
+
and this permission notice appear in all copies.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
14
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
15
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
16
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
17
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
18
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
19
|
+
THIS SOFTWARE.
|
package/dist/web/app.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*! GitRoll 0.1.0 · MIT License · Includes third-party software; see THIRD_PARTY_NOTICES.txt */
|
|
2
|
+
var xe=class extends Error{};var ce=t=>String(Math.abs(t)).padStart(2,"0");function yt(t=new Date){let e=-t.getTimezoneOffset(),n=e>=0?"+":"-";return`${t.getFullYear()}-${ce(t.getMonth()+1)}-${ce(t.getDate())}T${ce(t.getHours())}:${ce(t.getMinutes())}:${ce(t.getSeconds())}${n}${ce(Math.floor(Math.abs(e)/60))}:${ce(Math.abs(e)%60)}`}function Yt(t){return t.normalize("NFKD").replace(/[̀-ͯ]/g,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64).replace(/-+$/,"")}var Hn={$:"USD","€":"EUR","£":"GBP","¥":"JPY"};function Vt(t){let e=/^\s*([$€£¥])?\s*(-?[\d,]*\.?\d+)\s*([a-z]{3})?\s*$/i.exec(t);if(!e)return null;let n=Number(e[2].replace(/,/g,""));return Number.isFinite(n)?{value:n,currency:(e[3]??(e[1]?Hn[e[1]]:"USD")).toUpperCase()}:null}function Jt(t){let e="";for(let n=0;n<t.length;n+=32768)e+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(e)}var Z=class extends Error{},ee=class extends Error{};async function fe(t,e,n){let s;try{s=await fetch(`api/${e}`,{method:t,headers:{"Content-Type":"application/json"},body:n===void 0?void 0:JSON.stringify(n),cache:"no-store"})}catch{throw new Z("GitRoll has stopped. Start it again from your terminal with: gitroll")}let i=await s.json().catch(()=>null);if(s.status===401)throw new ee(i?.error??"Open GitRoll from the link shown in your terminal.");if(!s.ok||i===null)throw new xe(i?.error??`Something went wrong (${s.status}).`);return i}var Ue=class t{#e;#t="";static async connect(){let e=new t;try{return await e.refresh(),{store:e}}catch(n){return{error:n instanceof ee?"signed-out":"stopped"}}}info=()=>this.#e.info;version=()=>this.#t;entries=()=>this.#e.entries;projects=()=>this.#e.projects;types=()=>this.#e.types;async refresh(){let e;try{e=await fetch("api/state",{cache:"no-store"})}catch{throw new Z("GitRoll has stopped.")}if(e.status===401)throw new ee("Open GitRoll from the link shown in your terminal.");if(!e.ok||!(e.headers.get("content-type")??"").includes("application/json"))throw new Z("GitRoll has stopped.");let n=await e.text();n!==this.#t&&(this.#e=JSON.parse(n),this.#t=n)}async#n(e){let n=this.#e.info.maxAttachmentBytes,s=e.find(i=>i.size>n);if(s)throw new xe(`${s.name} is too large. Files can be up to ${Math.round(n/1048576)} MB.`);return Promise.all(e.map(async i=>({name:i.name,type:i.type,data:Jt(new Uint8Array(await i.arrayBuffer()))})))}async addEntry(e,n){let s=await fe("POST","entries",{...e,files:await this.#n(n)});return await this.refresh(),s}async updateEntry(e,n,s){let i=await fe("PATCH",`entries/${encodeURIComponent(e)}`,{...n,files:await this.#n(s)});return await this.refresh(),i}async deleteEntry(e){await fe("DELETE",`entries/${encodeURIComponent(e)}`),await this.refresh()}async createProject(e){let{project:n}=await fe("POST","projects",{name:e});return await this.refresh(),n}async history(e){return(await fe("GET",`entries/${encodeURIComponent(e)}/history`)).history}attachmentUrl(e){return`attachments/${encodeURIComponent(e.hash)}`}async sync(){let e=await fe("POST","sync",{});return await this.refresh(),e}ask(e){return fe("POST","ask",{question:e})}};var qe=Symbol.for("yaml.alias"),Gt=Symbol.for("yaml.document"),H=Symbol.for("yaml.map"),bt=Symbol.for("yaml.pair"),ke=Symbol.for("yaml.scalar"),te=Symbol.for("yaml.seq"),_=Symbol.for("yaml.node.type"),K=t=>!!t&&typeof t=="object"&&t[_]===qe,Y=t=>!!t&&typeof t=="object"&&t[_]===Gt,W=t=>!!t&&typeof t=="object"&&t[_]===H,k=t=>!!t&&typeof t=="object"&&t[_]===bt,S=t=>!!t&&typeof t=="object"&&t[_]===ke,V=t=>!!t&&typeof t=="object"&&t[_]===te;function L(t){if(t&&typeof t=="object")switch(t[_]){case H:case te:return!0}return!1}function v(t){if(t&&typeof t=="object")switch(t[_]){case qe:case H:case ke:case te:return!0}return!1}var He=t=>(S(t)||L(t))&&!!t.anchor;var D=Symbol("break visit"),Wt=Symbol("skip children"),J=Symbol("remove node");function z(t,e){let n=zt(e);Y(t)?ve(null,t.contents,n,Object.freeze([t]))===J&&(t.contents=null):ve(null,t,n,Object.freeze([]))}z.BREAK=D;z.SKIP=Wt;z.REMOVE=J;function ve(t,e,n,s){let i=Qt(t,e,n,s);if(v(i)||k(i))return Xt(t,s,i),ve(t,i,n,s);if(typeof i!="symbol"){if(L(e)){s=Object.freeze(s.concat(e));for(let r=0;r<e.items.length;++r){let o=ve(r,e.items[r],n,s);if(typeof o=="number")r=o-1;else{if(o===D)return D;o===J&&(e.items.splice(r,1),r-=1)}}}else if(k(e)){s=Object.freeze(s.concat(e));let r=ve("key",e.key,n,s);if(r===D)return D;r===J&&(e.key=null);let o=ve("value",e.value,n,s);if(o===D)return D;o===J&&(e.value=null)}}return i}async function Ye(t,e){let n=zt(e);Y(t)?await Te(null,t.contents,n,Object.freeze([t]))===J&&(t.contents=null):await Te(null,t,n,Object.freeze([]))}Ye.BREAK=D;Ye.SKIP=Wt;Ye.REMOVE=J;async function Te(t,e,n,s){let i=await Qt(t,e,n,s);if(v(i)||k(i))return Xt(t,s,i),Te(t,i,n,s);if(typeof i!="symbol"){if(L(e)){s=Object.freeze(s.concat(e));for(let r=0;r<e.items.length;++r){let o=await Te(r,e.items[r],n,s);if(typeof o=="number")r=o-1;else{if(o===D)return D;o===J&&(e.items.splice(r,1),r-=1)}}}else if(k(e)){s=Object.freeze(s.concat(e));let r=await Te("key",e.key,n,s);if(r===D)return D;r===J&&(e.key=null);let o=await Te("value",e.value,n,s);if(o===D)return D;o===J&&(e.value=null)}}return i}function zt(t){return typeof t=="object"&&(t.Collection||t.Node||t.Value)?Object.assign({Alias:t.Node,Map:t.Node,Scalar:t.Node,Seq:t.Node},t.Value&&{Map:t.Value,Scalar:t.Value,Seq:t.Value},t.Collection&&{Map:t.Collection,Seq:t.Collection},t):t}function Qt(t,e,n,s){if(typeof n=="function")return n(t,e,s);if(W(e))return n.Map?.(t,e,s);if(V(e))return n.Seq?.(t,e,s);if(k(e))return n.Pair?.(t,e,s);if(S(e))return n.Scalar?.(t,e,s);if(K(e))return n.Alias?.(t,e,s)}function Xt(t,e,n){let s=e[e.length-1];if(L(s))s.items[t]=n;else if(k(s))t==="key"?s.key=n:s.value=n;else if(Y(s))s.contents=n;else{let i=K(s)?"alias":"scalar";throw new Error(`Cannot replace node with ${i} parent`)}}var Yn={"!":"%21",",":"%2C","[":"%5B","]":"%5D","{":"%7B","}":"%7D"},Vn=t=>t.replace(/[!,[\]{}]/g,e=>Yn[e]),$e=class t{constructor(e,n){this.docStart=null,this.docEnd=!1,this.yaml=Object.assign({},t.defaultYaml,e),this.tags=Object.assign({},t.defaultTags,n)}clone(){let e=new t(this.yaml,this.tags);return e.docStart=this.docStart,e}atDocument(){let e=new t(this.yaml,this.tags);switch(this.yaml.version){case"1.1":this.atNextDocument=!0;break;case"1.2":this.atNextDocument=!1,this.yaml={explicit:t.defaultYaml.explicit,version:"1.2"},this.tags=Object.assign({},t.defaultTags);break}return e}add(e,n){this.atNextDocument&&(this.yaml={explicit:t.defaultYaml.explicit,version:"1.1"},this.tags=Object.assign({},t.defaultTags),this.atNextDocument=!1);let s=e.trim().split(/[ \t]+/),i=s.shift();switch(i){case"%TAG":{if(s.length!==2&&(n(0,"%TAG directive should contain exactly two parts"),s.length<2))return!1;let[r,o]=s;return this.tags[r]=o,!0}case"%YAML":{if(this.yaml.explicit=!0,s.length!==1)return n(0,"%YAML directive should contain exactly one part"),!1;let[r]=s;if(r==="1.1"||r==="1.2")return this.yaml.version=r,!0;{let o=/^\d+\.\d+$/.test(r);return n(6,`Unsupported YAML version ${r}`,o),!1}}default:return n(0,`Unknown directive ${i}`,!0),!1}}tagName(e,n){if(e==="!")return"!";if(e[0]!=="!")return n(`Not a valid tag: ${e}`),null;if(e[1]==="<"){let o=e.slice(2,-1);return o==="!"||o==="!!"?(n(`Verbatim tags aren't resolved, so ${e} is invalid.`),null):(e[e.length-1]!==">"&&n("Verbatim tags must end with a >"),o)}let[,s,i]=e.match(/^(.*!)([^!]*)$/s);i||n(`The ${e} tag has no suffix`);let r=this.tags[s];if(r)try{return r+decodeURIComponent(i)}catch(o){return n(String(o)),null}return s==="!"?e:(n(`Could not resolve tag: ${e}`),null)}tagString(e){for(let[n,s]of Object.entries(this.tags))if(e.startsWith(s))return n+Vn(e.substring(s.length));return e[0]==="!"?e:`!<${e}>`}toString(e){let n=this.yaml.explicit?[`%YAML ${this.yaml.version||"1.2"}`]:[],s=Object.entries(this.tags),i;if(e&&s.length>0&&v(e.contents)){let r={};z(e.contents,(o,c)=>{v(c)&&c.tag&&(r[c.tag]=!0)}),i=Object.keys(r)}else i=[];for(let[r,o]of s)r==="!!"&&o==="tag:yaml.org,2002:"||(!e||i.some(c=>c.startsWith(o)))&&n.push(`%TAG ${r} ${o}`);return n.join(`
|
|
3
|
+
`)}};$e.defaultYaml={explicit:!1,version:"1.2"};$e.defaultTags={"!!":"tag:yaml.org,2002:"};function Ve(t){if(/[\x00-\x19\s,[\]{}]/.test(t)){let n=`Anchor must not contain whitespace or control characters: ${JSON.stringify(t)}`;throw new Error(n)}return!0}function ue(t,e,n,s){if(s&&typeof s=="object")if(Array.isArray(s))for(let i=0,r=s.length;i<r;++i){let o=s[i],c=ue(t,s,String(i),o);c===void 0?delete s[i]:c!==o&&(s[i]=c)}else if(s instanceof Map)for(let i of Array.from(s.keys())){let r=s.get(i),o=ue(t,s,i,r);o===void 0?s.delete(i):o!==r&&s.set(i,o)}else if(s instanceof Set)for(let i of Array.from(s)){let r=ue(t,s,i,i);r===void 0?s.delete(i):r!==i&&(s.delete(i),s.add(r))}else for(let[i,r]of Object.entries(s)){let o=ue(t,s,i,r);o===void 0?delete s[i]:o!==r&&(s[i]=o)}return t.call(e,n,s)}function C(t,e,n){if(Array.isArray(t))return t.map((s,i)=>C(s,String(i),n));if(t&&typeof t.toJSON=="function"){if(!n||!He(t))return t.toJSON(e,n);let s={aliasCount:0,count:1,res:void 0};n.anchors.set(t,s),n.onCreate=r=>{s.res=r,delete n.onCreate};let i=t.toJSON(e,n);return n.onCreate&&n.onCreate(i),i}return typeof t=="bigint"&&!n?.keep?Number(t):t}var ne=class{constructor(e){Object.defineProperty(this,_,{value:e})}clone(){let e=Object.create(Object.getPrototypeOf(this),Object.getOwnPropertyDescriptors(this));return this.range&&(e.range=this.range.slice()),e}toJS(e,{mapAsMap:n,maxAliasCount:s,onAnchor:i,reviver:r}={}){if(!Y(e))throw new TypeError("A document argument is required");let o={anchors:new Map,doc:e,keep:!0,mapAsMap:n===!0,mapKeyWarned:!1,maxAliasCount:typeof s=="number"?s:100},c=C(this,"",o);if(typeof i=="function")for(let{count:a,res:l}of o.anchors.values())i(l,a);return typeof r=="function"?ue(r,{"":c},"",c):c}};var pe=class extends ne{constructor(e){super(qe),this.source=e,Object.defineProperty(this,"tag",{set(){throw new Error("Alias nodes cannot have tags")}})}resolve(e,n){if(n?.maxAliasCount===0)throw new ReferenceError("Alias resolution is disabled");let s;n?.aliasResolveCache?s=n.aliasResolveCache:(s=[],z(e,{Node:(r,o)=>{(K(o)||He(o))&&s.push(o)}}),n&&(n.aliasResolveCache=s));let i;for(let r of s){if(r===this)break;r.anchor===this.source&&(i=r)}if(i&&n){let{anchors:r,doc:o,maxAliasCount:c}=n,a=r.get(i);if(a||(C(i,null,n),a=r.get(i)),a?.res===void 0){let l="This should not happen: Alias anchor was not resolved?";throw new ReferenceError(l)}if(c>=0&&(a.count+=1,a.aliasCount===0&&(a.aliasCount=Je(o,i,r)),a.count*a.aliasCount>c)){let l="Excessive alias count indicates a resource exhaustion attack";throw new ReferenceError(l)}}return i}toJSON(e,n){if(!n)return{source:this.source};let s=this.resolve(n.doc,n);if(!s){let i=`Unresolved alias (the anchor must be set before the alias): ${this.source}`;throw new ReferenceError(i)}return n.anchors.get(s).res}toString(e,n,s){let i=`*${this.source}`;if(e){if(Ve(this.source),e.options.verifyAliasOrder&&!e.anchors.has(this.source)){let r=`Unresolved alias (the anchor must be set before the alias): ${this.source}`;throw new Error(r)}if(e.implicitKey)return`${i} `}return i}};function Je(t,e,n){if(K(e)){let s=e.resolve(t),i=n&&s&&n.get(s);return i?i.count*i.aliasCount:0}else if(L(e)){let s=0;for(let i of e.items){let r=Je(t,i,n);r>s&&(s=r)}return s}else if(k(e)){let s=Je(t,e.key,n),i=Je(t,e.value,n);return Math.max(s,i)}return 1}var Ge=t=>!t||typeof t!="function"&&typeof t!="object",w=class extends ne{constructor(e){super(ke),this.value=e}toJSON(e,n){return n?.keep?this.value:C(this.value,e,n)}toString(){return String(this.value)}};w.BLOCK_FOLDED="BLOCK_FOLDED";w.BLOCK_LITERAL="BLOCK_LITERAL";w.PLAIN="PLAIN";w.QUOTE_DOUBLE="QUOTE_DOUBLE";w.QUOTE_SINGLE="QUOTE_SINGLE";var Jn="tag:yaml.org,2002:";function Gn(t,e,n){if(e){let s=n.filter(r=>r.tag===e),i=s.find(r=>!r.format)??s[0];if(!i)throw new Error(`Tag ${e} not found`);return i}return n.find(s=>s.identify?.(t)&&!s.format)}function se(t,e,n){if(Y(t)&&(t=t.contents),v(t))return t;if(k(t)){let f=n.schema[H].createNode?.(n.schema,null,n);return f.items.push(t),f}(t instanceof String||t instanceof Number||t instanceof Boolean||typeof BigInt<"u"&&t instanceof BigInt)&&(t=t.valueOf());let{aliasDuplicateObjects:s,onAnchor:i,onTagObj:r,schema:o,sourceObjects:c}=n,a;if(s&&t&&typeof t=="object"){if(a=c.get(t),a)return a.anchor??(a.anchor=i(t)),new pe(a.anchor);a={anchor:null,node:null},c.set(t,a)}e?.startsWith("!!")&&(e=Jn+e.slice(2));let l=Gn(t,e,o.tags);if(!l){if(t&&typeof t.toJSON=="function"&&(t=t.toJSON()),!t||typeof t!="object"){let f=new w(t);return a&&(a.node=f),f}l=t instanceof Map?o[H]:Symbol.iterator in Object(t)?o[te]:o[H]}r&&(r(l),delete n.onTagObj);let m=l?.createNode?l.createNode(n.schema,t,n):typeof l?.nodeClass?.from=="function"?l.nodeClass.from(n.schema,t,n):new w(t);return e?m.tag=e:l.default||(m.tag=l.tag),a&&(a.node=m),m}function wt(t,e,n){let s=n;for(let i=e.length-1;i>=0;--i){let r=e[i];if(typeof r=="number"&&Number.isInteger(r)&&r>=0){let o=[];o[r]=s,s=o}else s=new Map([[r,s]])}return se(s,void 0,{aliasDuplicateObjects:!1,keepUndefined:!1,onAnchor:()=>{throw new Error("This should not happen, please report a bug.")},schema:t,sourceObjects:new Map})}var Zt=t=>t==null||typeof t=="object"&&!!t[Symbol.iterator]().next().done,Ee=class extends ne{constructor(e,n){super(e),Object.defineProperty(this,"schema",{value:n,configurable:!0,enumerable:!1,writable:!0})}clone(e){let n=Object.create(Object.getPrototypeOf(this),Object.getOwnPropertyDescriptors(this));return e&&(n.schema=e),n.items=n.items.map(s=>v(s)||k(s)?s.clone(e):s),this.range&&(n.range=this.range.slice()),n}addIn(e,n){if(Zt(e))this.add(n);else{let[s,...i]=e,r=this.get(s,!0);if(L(r))r.addIn(i,n);else if(r===void 0&&this.schema)this.set(s,wt(this.schema,i,n));else throw new Error(`Expected YAML collection at ${s}. Remaining path: ${i}`)}}deleteIn(e){let[n,...s]=e;if(s.length===0)return this.delete(n);let i=this.get(n,!0);if(L(i))return i.deleteIn(s);throw new Error(`Expected YAML collection at ${n}. Remaining path: ${s}`)}getIn(e,n){let[s,...i]=e,r=this.get(s,!0);return i.length===0?!n&&S(r)?r.value:r:L(r)?r.getIn(i,n):void 0}hasAllNullValues(e){return this.items.every(n=>{if(!k(n))return!1;let s=n.value;return s==null||e&&S(s)&&s.value==null&&!s.commentBefore&&!s.comment&&!s.tag})}hasIn(e){let[n,...s]=e;if(s.length===0)return this.has(n);let i=this.get(n,!0);return L(i)?i.hasIn(s):!1}setIn(e,n){let[s,...i]=e;if(i.length===0)this.set(s,n);else{let r=this.get(s,!0);if(L(r))r.setIn(i,n);else if(r===void 0&&this.schema)this.set(s,wt(this.schema,i,n));else throw new Error(`Expected YAML collection at ${s}. Remaining path: ${i}`)}}};var en=t=>t.replace(/^(?!$)(?: $)?/gm,"#");function ie(t,e){return/^\n+$/.test(t)?t.substring(1):e?t.replace(/^(?! *$)/gm,e):t}var Q=(t,e,n)=>t.endsWith(`
|
|
4
|
+
`)?ie(n,e):n.includes(`
|
|
5
|
+
`)?`
|
|
6
|
+
`+ie(n,e):(t.endsWith(" ")?"":" ")+n;var St="flow",We="block",Me="quoted";function De(t,e,n="flow",{indentAtStart:s,lineWidth:i=80,minContentWidth:r=20,onFold:o,onOverflow:c}={}){if(!i||i<0)return t;i<r&&(r=0);let a=Math.max(1+r,1+i-e.length);if(t.length<=a)return t;let l=[],m={},f=i-e.length;typeof s=="number"&&(s>i-Math.max(2,r)?l.push(0):f=i-s);let d,b,T=!1,p=-1,h=-1,N=-1;n===We&&(p=tn(t,p,e.length),p!==-1&&(f=p+a));for(let E;E=t[p+=1];){if(n===Me&&E==="\\"){switch(h=p,t[p+1]){case"x":p+=3;break;case"u":p+=5;break;case"U":p+=9;break;default:p+=1}N=p}if(E===`
|
|
7
|
+
`)n===We&&(p=tn(t,p,e.length)),f=p+e.length+a,d=void 0;else{if(E===" "&&b&&b!==" "&&b!==`
|
|
8
|
+
`&&b!==" "){let A=t[p+1];A&&A!==" "&&A!==`
|
|
9
|
+
`&&A!==" "&&(d=p)}if(p>=f)if(d)l.push(d),f=d+a,d=void 0;else if(n===Me){for(;b===" "||b===" ";)b=E,E=t[p+=1],T=!0;let A=p>N+1?p-2:h-1;if(m[A])return t;l.push(A),m[A]=!0,f=A+a,d=void 0}else T=!0}b=E}if(T&&c&&c(),l.length===0)return t;o&&o();let $=t.slice(0,l[0]);for(let E=0;E<l.length;++E){let A=l[E],O=l[E+1]||t.length;A===0?$=`
|
|
10
|
+
${e}${t.slice(0,O)}`:(n===Me&&m[A]&&($+=`${t[A]}\\`),$+=`
|
|
11
|
+
${e}${t.slice(A+1,O)}`)}return $}function tn(t,e,n){let s=e,i=e+1,r=t[i];for(;r===" "||r===" ";)if(e<i+n)r=t[++e];else{do r=t[++e];while(r&&r!==`
|
|
12
|
+
`);s=e,i=e+1,r=t[i]}return s}var Qe=(t,e)=>({indentAtStart:e?t.indent.length:t.indentAtStart,lineWidth:t.options.lineWidth,minContentWidth:t.options.minContentWidth}),Xe=t=>/^(%|---|\.\.\.)/m.test(t);function Wn(t,e,n){if(!e||e<0)return!1;let s=e-n,i=t.length;if(i<=s)return!1;for(let r=0,o=0;r<i;++r)if(t[r]===`
|
|
13
|
+
`){if(r-o>s)return!0;if(o=r+1,i-o<=s)return!1}return!0}function Pe(t,e){let n=JSON.stringify(t);if(e.options.doubleQuotedAsJSON)return n;let{implicitKey:s}=e,i=e.options.doubleQuotedMinMultiLineLength,r=e.indent||(Xe(t)?" ":""),o="",c=0;for(let a=0,l=n[a];l;l=n[++a])if(l===" "&&n[a+1]==="\\"&&n[a+2]==="n"&&(o+=n.slice(c,a)+"\\ ",a+=1,c=a,l="\\"),l==="\\")switch(n[a+1]){case"u":{o+=n.slice(c,a);let m=n.substr(a+2,4);switch(m){case"0000":o+="\\0";break;case"0007":o+="\\a";break;case"000b":o+="\\v";break;case"001b":o+="\\e";break;case"0085":o+="\\N";break;case"00a0":o+="\\_";break;case"2028":o+="\\L";break;case"2029":o+="\\P";break;default:m.substr(0,2)==="00"?o+="\\x"+m.substr(2):o+=n.substr(a,6)}a+=5,c=a+1}break;case"n":if(s||n[a+2]==='"'||n.length<i)a+=1;else{for(o+=n.slice(c,a)+`
|
|
14
|
+
|
|
15
|
+
`;n[a+2]==="\\"&&n[a+3]==="n"&&n[a+4]!=='"';)o+=`
|
|
16
|
+
`,a+=2;o+=r,n[a+2]===" "&&(o+="\\"),a+=1,c=a+1}break;default:a+=1}return o=c?o+n.slice(c):n,s?o:De(o,r,Me,Qe(e,!1))}function kt(t,e){if(e.options.singleQuote===!1||e.implicitKey&&t.includes(`
|
|
17
|
+
`)||/[ \t]\n|\n[ \t]/.test(t))return Pe(t,e);let n=e.indent||(Xe(t)?" ":""),s="'"+t.replace(/'/g,"''").replace(/\n+/g,`$&
|
|
18
|
+
${n}`)+"'";return e.implicitKey?s:De(s,n,St,Qe(e,!1))}function Ne(t,e){let{singleQuote:n}=e.options,s;if(n===!1)s=Pe;else{let i=t.includes('"'),r=t.includes("'");i&&!r?s=kt:r&&!i?s=Pe:s=n?kt:Pe}return s(t,e)}var vt;try{vt=new RegExp(`(^|(?<!
|
|
19
|
+
))
|
|
20
|
+
+(?!
|
|
21
|
+
|$)`,"g")}catch{vt=/\n+(?!\n|$)/g}function ze({comment:t,type:e,value:n},s,i,r){let{blockQuote:o,commentString:c,lineWidth:a}=s.options;if(!o||/\n[\t ]+$/.test(n))return Ne(n,s);let l=s.indent||(s.forceBlockIndent||Xe(n)?" ":""),m=o==="literal"?!0:o==="folded"||e===w.BLOCK_FOLDED?!1:e===w.BLOCK_LITERAL?!0:!Wn(n,a,l.length);if(!n)return m?`|
|
|
22
|
+
`:`>
|
|
23
|
+
`;let f,d;for(d=n.length;d>0;--d){let O=n[d-1];if(O!==`
|
|
24
|
+
`&&O!==" "&&O!==" ")break}let b=n.substring(d),T=b.indexOf(`
|
|
25
|
+
`);T===-1?f="-":n===b||T!==b.length-1?(f="+",r&&r()):f="",b&&(n=n.slice(0,-b.length),b[b.length-1]===`
|
|
26
|
+
`&&(b=b.slice(0,-1)),b=b.replace(vt,`$&${l}`));let p=!1,h,N=-1;for(h=0;h<n.length;++h){let O=n[h];if(O===" ")p=!0;else if(O===`
|
|
27
|
+
`)N=h;else break}let $=n.substring(0,N<h?N+1:h);$&&(n=n.substring($.length),$=$.replace(/\n+/g,`$&${l}`));let A=(p?l?"2":"1":"")+f;if(t&&(A+=" "+c(t.replace(/ ?[\r\n]+/g," ")),i&&i()),!m){let O=n.replace(/\n+/g,`
|
|
28
|
+
$&`).replace(/(?:^|\n)([\t ].*)(?:([\n\t ]*)\n(?![\n\t ]))?/g,"$1$2").replace(/\n+/g,`$&${l}`),F=!1,q=Qe(s,!0);o!=="folded"&&e!==w.BLOCK_FOLDED&&(q.onOverflow=()=>{F=!0});let je=De(`${$}${O}${b}`,l,We,q);if(!F)return`>${A}
|
|
29
|
+
${l}${je}`}return n=n.replace(/\n+/g,`$&${l}`),`|${A}
|
|
30
|
+
${l}${$}${n}${b}`}function zn(t,e,n,s){let{type:i,value:r}=t,{actualString:o,implicitKey:c,indent:a,indentStep:l,inFlow:m}=e;if(c&&r.includes(`
|
|
31
|
+
`)||m&&/[[\]{},]/.test(r))return Ne(r,e);if(/^[\n\t ,[\]{}#&*!|>'"%@`]|^[?-]$|^[?-][ \t]|[\n:][ \t]|[ \t]\n|[\n\t ]#|[\n\t :]$/.test(r))return c||m||!r.includes(`
|
|
32
|
+
`)?Ne(r,e):ze(t,e,n,s);if(!c&&!m&&i!==w.PLAIN&&r.includes(`
|
|
33
|
+
`))return ze(t,e,n,s);if(Xe(r)){if(a==="")return e.forceBlockIndent=!0,ze(t,e,n,s);if(c&&a===l)return Ne(r,e)}let f=r.replace(/\n+/g,`$&
|
|
34
|
+
${a}`);if(o){let d=p=>p.default&&p.tag!=="tag:yaml.org,2002:str"&&p.test?.test(f),{compat:b,tags:T}=e.doc.schema;if(T.some(d)||b?.some(d))return Ne(r,e)}return c?f:De(f,a,St,Qe(e,!1))}function _e(t,e,n,s){let{implicitKey:i,inFlow:r}=e,o=typeof t.value=="string"?t:Object.assign({},t,{value:String(t.value)}),{type:c}=t;c!==w.QUOTE_DOUBLE&&/[\x00-\x08\x0b-\x1f\x7f-\x9f\u{D800}-\u{DFFF}]/u.test(o.value)&&(c=w.QUOTE_DOUBLE);let a=m=>{switch(m){case w.BLOCK_FOLDED:case w.BLOCK_LITERAL:return i||r?Ne(o.value,e):ze(o,e,n,s);case w.QUOTE_DOUBLE:return Pe(o.value,e);case w.QUOTE_SINGLE:return kt(o.value,e);case w.PLAIN:return zn(o,e,n,s);default:return null}},l=a(c);if(l===null){let{defaultKeyType:m,defaultStringType:f}=e.options,d=i&&m||f;if(l=a(d),l===null)throw new Error(`Unsupported default string type ${d}`)}return l}function Tt(t,e){let n=Object.assign({blockQuote:!0,commentString:en,defaultKeyType:null,defaultStringType:"PLAIN",directives:null,doubleQuotedAsJSON:!1,doubleQuotedMinMultiLineLength:40,falseStr:"false",flowCollectionPadding:!0,indentSeq:!0,lineWidth:80,minContentWidth:20,nullStr:"null",simpleKeys:!1,singleQuote:null,trailingComma:!1,trueStr:"true",verifyAliasOrder:!0},t.schema.toStringOptions,e),s;switch(n.collectionStyle){case"block":s=!1;break;case"flow":s=!0;break;default:s=null}return{anchors:new Set,doc:t,flowCollectionPadding:n.flowCollectionPadding?" ":"",indent:"",indentStep:typeof n.indent=="number"?" ".repeat(n.indent):" ",inFlow:s,options:n}}function Qn(t,e){if(e.tag){let i=t.filter(r=>r.tag===e.tag);if(i.length>0)return i.find(r=>r.format===e.format)??i[0]}let n,s;if(S(e)){s=e.value;let i=t.filter(r=>r.identify?.(s));if(i.length>1){let r=i.filter(o=>o.test);r.length>0&&(i=r)}n=i.find(r=>r.format===e.format)??i.find(r=>!r.format)}else s=e,n=t.find(i=>i.nodeClass&&s instanceof i.nodeClass);if(!n){let i=s?.constructor?.name??(s===null?"null":typeof s);throw new Error(`Tag not resolved for ${i} value`)}return n}function Xn(t,e,{anchors:n,doc:s}){if(!s.directives)return"";let i=[],r=(S(t)||L(t))&&t.anchor;r&&Ve(r)&&(n.add(r),i.push(`&${r}`));let o=t.tag??(e.default?null:e.tag);return o&&i.push(s.directives.tagString(o)),i.join(" ")}function de(t,e,n,s){if(k(t))return t.toString(e,n,s);if(K(t)){if(e.doc.directives)return t.toString(e);if(e.resolvedAliases?.has(t))throw new TypeError("Cannot stringify circular structure without alias nodes");e.resolvedAliases?e.resolvedAliases.add(t):e.resolvedAliases=new Set([t]),t=t.resolve(e.doc)}let i,r=v(t)?t:e.doc.createNode(t,{onTagObj:a=>i=a});i??(i=Qn(e.doc.schema.tags,r));let o=Xn(r,i,e);o.length>0&&(e.indentAtStart=(e.indentAtStart??0)+o.length+1);let c=typeof i.stringify=="function"?i.stringify(r,e,n,s):S(r)?_e(r,e,n,s):r.toString(e,n,s);return o?S(r)||c[0]==="{"||c[0]==="["?`${o} ${c}`:`${o}
|
|
35
|
+
${e.indent}${c}`:c}function nn({key:t,value:e},n,s,i){let{allNullValues:r,doc:o,indent:c,indentStep:a,options:{commentString:l,indentSeq:m,simpleKeys:f}}=n,d=v(t)&&t.comment||null;if(f){if(d)throw new Error("With simple keys, key nodes cannot have comments");if(L(t)||!v(t)&&typeof t=="object"){let q="With simple keys, collection cannot be used as a key value";throw new Error(q)}}let b=!f&&(!t||d&&e==null&&!n.inFlow||L(t)||(S(t)?t.type===w.BLOCK_FOLDED||t.type===w.BLOCK_LITERAL:typeof t=="object"));n=Object.assign({},n,{allNullValues:!1,implicitKey:!b&&(f||!r),indent:c+a});let T=!1,p=!1,h=de(t,n,()=>T=!0,()=>p=!0);if(!b&&!n.inFlow&&h.length>1024){if(f)throw new Error("With simple keys, single line scalar must not span more than 1024 characters");b=!0}if(n.inFlow){if(r||e==null)return T&&s&&s(),h===""?"?":b?`? ${h}`:h}else if(r&&!f||e==null&&b)return h=`? ${h}`,d&&!T?h+=Q(h,n.indent,l(d)):p&&i&&i(),h;T&&(d=null),b?(d&&(h+=Q(h,n.indent,l(d))),h=`? ${h}
|
|
36
|
+
${c}:`):(h=`${h}:`,d&&(h+=Q(h,n.indent,l(d))));let N,$,E;v(e)?(N=!!e.spaceBefore,$=e.commentBefore,E=e.comment):(N=!1,$=null,E=null,e&&typeof e=="object"&&(e=o.createNode(e))),n.implicitKey=!1,!b&&!d&&S(e)&&(n.indentAtStart=h.length+1),p=!1,!m&&a.length>=2&&!n.inFlow&&!b&&V(e)&&!e.flow&&!e.tag&&!e.anchor&&(n.indent=n.indent.substring(2));let A=!1,O=de(e,n,()=>A=!0,()=>p=!0),F=" ";if(d||N||$){if(F=N?`
|
|
37
|
+
`:"",$){let q=l($);F+=`
|
|
38
|
+
${ie(q,n.indent)}`}O===""&&!n.inFlow?F===`
|
|
39
|
+
`&&E&&(F=`
|
|
40
|
+
|
|
41
|
+
`):F+=`
|
|
42
|
+
${n.indent}`}else if(!b&&L(e)){let q=O[0],je=O.indexOf(`
|
|
43
|
+
`),qt=je!==-1,qn=n.inFlow??e.flow??e.items.length===0;if(qt||!qn){let Ht=!1;if(qt&&(q==="&"||q==="!")){let le=O.indexOf(" ");q==="&"&&le!==-1&&le<je&&O[le+1]==="!"&&(le=O.indexOf(" ",le+1)),(le===-1||je<le)&&(Ht=!0)}Ht||(F=`
|
|
44
|
+
${n.indent}`)}}else(O===""||O[0]===`
|
|
45
|
+
`)&&(F="");return h+=F+O,n.inFlow?A&&s&&s():E&&!A?h+=Q(h,n.indent,l(E)):p&&i&&i(),h}function $t(t,e){(t==="debug"||t==="warn")&&console.warn(e)}var Ze="<<",Be={identify:t=>t===Ze||typeof t=="symbol"&&t.description===Ze,default:"key",tag:"tag:yaml.org,2002:merge",test:/^<<$/,resolve:()=>Object.assign(new w(Symbol(Ze)),{addToJSMap:Nt}),stringify:()=>Ze},sn=(t,e)=>(Be.identify(e)||S(e)&&(!e.type||e.type===w.PLAIN)&&Be.identify(e.value))&&t?.doc.schema.tags.some(n=>n.tag===Be.tag&&n.default);function Nt(t,e,n){let s=rn(t,n);if(V(s))for(let i of s.items)Et(t,e,i);else if(Array.isArray(s))for(let i of s)Et(t,e,i);else Et(t,e,s)}function Et(t,e,n){let s=rn(t,n);if(!W(s))throw new Error("Merge sources must be maps or map aliases");let i=s.toJSON(null,t,Map);for(let[r,o]of i)e instanceof Map?e.has(r)||e.set(r,o):e instanceof Set?e.add(r):Object.prototype.hasOwnProperty.call(e,r)||Object.defineProperty(e,r,{value:o,writable:!0,enumerable:!0,configurable:!0});return e}function rn(t,e){return t&&K(e)?e.resolve(t.doc,t):e}function et(t,e,{key:n,value:s}){if(v(n)&&n.addToJSMap)n.addToJSMap(t,e,s);else if(sn(t,n))Nt(t,e,s);else{let i=C(n,"",t);if(e instanceof Map)e.set(i,C(s,i,t));else if(e instanceof Set)e.add(i);else{let r=Zn(n,i,t),o=C(s,r,t);r in e?Object.defineProperty(e,r,{value:o,writable:!0,enumerable:!0,configurable:!0}):e[r]=o}}return e}function Zn(t,e,n){if(e===null)return"";if(typeof e!="object")return String(e);if(v(t)&&n?.doc){let s=Tt(n.doc,{});s.anchors=new Set;for(let r of n.anchors.keys())s.anchors.add(r.anchor);s.inFlow=!0,s.inStringifyKey=!0;let i=t.toString(s);if(!n.mapKeyWarned){let r=JSON.stringify(i);r.length>40&&(r=r.substring(0,36)+'..."'),$t(n.doc.options.logLevel,`Keys with collection values will be stringified due to JS Object restrictions: ${r}. Set mapAsMap: true to use object keys.`),n.mapKeyWarned=!0}return i}return JSON.stringify(e)}function Le(t,e,n){let s=se(t,void 0,n),i=se(e,void 0,n);return new M(s,i)}var M=class t{constructor(e,n=null){Object.defineProperty(this,_,{value:bt}),this.key=e,this.value=n}clone(e){let{key:n,value:s}=this;return v(n)&&(n=n.clone(e)),v(s)&&(s=s.clone(e)),new t(n,s)}toJSON(e,n){let s=n?.mapAsMap?new Map:{};return et(n,s,this)}toString(e,n,s){return e?.doc?nn(this,e,n,s):JSON.stringify(this)}};function nt(t,e,n){return(e.inFlow??t.flow?ts:es)(t,e,n)}function es({comment:t,items:e},n,{blockItemPrefix:s,flowChars:i,itemIndent:r,onChompKeep:o,onComment:c}){let{indent:a,options:{commentString:l}}=n,m=Object.assign({},n,{indent:r,type:null}),f=!1,d=[];for(let T=0;T<e.length;++T){let p=e[T],h=null;if(v(p))!f&&p.spaceBefore&&d.push(""),tt(n,d,p.commentBefore,f),p.comment&&(h=p.comment);else if(k(p)){let $=v(p.key)?p.key:null;$&&(!f&&$.spaceBefore&&d.push(""),tt(n,d,$.commentBefore,f))}f=!1;let N=de(p,m,()=>h=null,()=>f=!0);h&&(N+=Q(N,r,l(h))),f&&h&&(f=!1),d.push(s+N)}let b;if(d.length===0)b=i.start+i.end;else{b=d[0];for(let T=1;T<d.length;++T){let p=d[T];b+=p?`
|
|
46
|
+
${a}${p}`:`
|
|
47
|
+
`}}return t?(b+=`
|
|
48
|
+
`+ie(l(t),a),c&&c()):f&&o&&o(),b}function ts({items:t},e,{flowChars:n,itemIndent:s}){let{indent:i,indentStep:r,flowCollectionPadding:o,options:{commentString:c}}=e;s+=r;let a=Object.assign({},e,{indent:s,inFlow:!0,type:null}),l=!1,m=0,f=[];for(let T=0;T<t.length;++T){let p=t[T],h=null;if(v(p))p.spaceBefore&&f.push(""),tt(e,f,p.commentBefore,!1),p.comment&&(h=p.comment);else if(k(p)){let $=v(p.key)?p.key:null;$&&($.spaceBefore&&f.push(""),tt(e,f,$.commentBefore,!1),$.comment&&(l=!0));let E=v(p.value)?p.value:null;E?(E.comment&&(h=E.comment),E.commentBefore&&(l=!0)):p.value==null&&$?.comment&&(h=$.comment)}h&&(l=!0);let N=de(p,a,()=>h=null);l||(l=f.length>m||N.includes(`
|
|
49
|
+
`)),T<t.length-1?N+=",":e.options.trailingComma&&(e.options.lineWidth>0&&(l||(l=f.reduce(($,E)=>$+E.length+2,2)+(N.length+2)>e.options.lineWidth)),l&&(N+=",")),h&&(N+=Q(N,s,c(h))),f.push(N),m=f.length}let{start:d,end:b}=n;if(f.length===0)return d+b;if(!l){let T=f.reduce((p,h)=>p+h.length+2,2);l=e.options.lineWidth>0&&T>e.options.lineWidth}if(l){let T=d;for(let p of f)T+=p?`
|
|
50
|
+
${r}${i}${p}`:`
|
|
51
|
+
`;return`${T}
|
|
52
|
+
${i}${b}`}else return`${d}${o}${f.join(" ")}${o}${b}`}function tt({indent:t,options:{commentString:e}},n,s,i){if(s&&i&&(s=s.replace(/^\n+/,"")),s){let r=ie(e(s),t);n.push(r.trimStart())}}function re(t,e){let n=S(e)?e.value:e;for(let s of t)if(k(s)&&(s.key===e||s.key===n||S(s.key)&&s.key.value===n))return s}var j=class extends Ee{static get tagName(){return"tag:yaml.org,2002:map"}constructor(e){super(H,e),this.items=[]}static from(e,n,s){let{keepUndefined:i,replacer:r}=s,o=new this(e),c=(a,l)=>{if(typeof r=="function")l=r.call(n,a,l);else if(Array.isArray(r)&&!r.includes(a))return;(l!==void 0||i)&&o.items.push(Le(a,l,s))};if(n instanceof Map)for(let[a,l]of n)c(a,l);else if(n&&typeof n=="object")for(let a of Object.keys(n))c(a,n[a]);return typeof e.sortMapEntries=="function"&&o.items.sort(e.sortMapEntries),o}add(e,n){let s;k(e)?s=e:!e||typeof e!="object"||!("key"in e)?s=new M(e,e?.value):s=new M(e.key,e.value);let i=re(this.items,s.key),r=this.schema?.sortMapEntries;if(i){if(!n)throw new Error(`Key ${s.key} already set`);S(i.value)&&Ge(s.value)?i.value.value=s.value:i.value=s.value}else if(r){let o=this.items.findIndex(c=>r(s,c)<0);o===-1?this.items.push(s):this.items.splice(o,0,s)}else this.items.push(s)}delete(e){let n=re(this.items,e);return n?this.items.splice(this.items.indexOf(n),1).length>0:!1}get(e,n){let i=re(this.items,e)?.value;return(!n&&S(i)?i.value:i)??void 0}has(e){return!!re(this.items,e)}set(e,n){this.add(new M(e,n),!0)}toJSON(e,n,s){let i=s?new s:n?.mapAsMap?new Map:{};n?.onCreate&&n.onCreate(i);for(let r of this.items)et(n,i,r);return i}toString(e,n,s){if(!e)return JSON.stringify(this);for(let i of this.items)if(!k(i))throw new Error(`Map items must all be pairs; found ${JSON.stringify(i)} instead`);return!e.allNullValues&&this.hasAllNullValues(!1)&&(e=Object.assign({},e,{allNullValues:!0})),nt(this,e,{blockItemPrefix:"",flowChars:{start:"{",end:"}"},itemIndent:e.indent||"",onChompKeep:s,onComment:n})}};var Ae={collection:"map",default:!0,nodeClass:j,tag:"tag:yaml.org,2002:map",resolve(t,e){return W(t)||e("Expected a mapping for this tag"),t},createNode:(t,e,n)=>j.from(t,e,n)};var B=class extends Ee{static get tagName(){return"tag:yaml.org,2002:seq"}constructor(e){super(te,e),this.items=[]}add(e){this.items.push(e)}delete(e){let n=st(e);return typeof n!="number"?!1:this.items.splice(n,1).length>0}get(e,n){let s=st(e);if(typeof s!="number")return;let i=this.items[s];return!n&&S(i)?i.value:i}has(e){let n=st(e);return typeof n=="number"&&n<this.items.length}set(e,n){let s=st(e);if(typeof s!="number")throw new Error(`Expected a valid index, not ${e}.`);let i=this.items[s];S(i)&&Ge(n)?i.value=n:this.items[s]=n}toJSON(e,n){let s=[];n?.onCreate&&n.onCreate(s);let i=0;for(let r of this.items)s.push(C(r,String(i++),n));return s}toString(e,n,s){return e?nt(this,e,{blockItemPrefix:"- ",flowChars:{start:"[",end:"]"},itemIndent:(e.indent||"")+" ",onChompKeep:s,onComment:n}):JSON.stringify(this)}static from(e,n,s){let{replacer:i}=s,r=new this(e);if(n&&Symbol.iterator in Object(n)){let o=0;for(let c of n){if(typeof i=="function"){let a=n instanceof Set?c:String(o++);c=i.call(n,a,c)}r.items.push(se(c,void 0,s))}}return r}};function st(t){let e=S(t)?t.value:t;return e&&typeof e=="string"&&(e=Number(e)),typeof e=="number"&&Number.isInteger(e)&&e>=0?e:null}var Oe={collection:"seq",default:!0,nodeClass:B,tag:"tag:yaml.org,2002:seq",resolve(t,e){return V(t)||e("Expected a sequence for this tag"),t},createNode:(t,e,n)=>B.from(t,e,n)};function an(t){return typeof t=="bigint"||Number.isInteger(t)}var rt=({value:t})=>JSON.stringify(t),cs=[{identify:t=>typeof t=="string",default:!0,tag:"tag:yaml.org,2002:str",resolve:t=>t,stringify:rt},{identify:t=>t==null,createNode:()=>new w(null),default:!0,tag:"tag:yaml.org,2002:null",test:/^null$/,resolve:()=>null,stringify:rt},{identify:t=>typeof t=="boolean",default:!0,tag:"tag:yaml.org,2002:bool",test:/^true$|^false$/,resolve:t=>t==="true",stringify:rt},{identify:an,default:!0,tag:"tag:yaml.org,2002:int",test:/^-?(?:0|[1-9][0-9]*)$/,resolve:(t,e,{intAsBigInt:n})=>n?BigInt(t):parseInt(t,10),stringify:({value:t})=>an(t)?t.toString():JSON.stringify(t)},{identify:t=>typeof t=="number",default:!0,tag:"tag:yaml.org,2002:float",test:/^-?(?:0|[1-9][0-9]*)(?:\.[0-9]*)?(?:[eE][-+]?[0-9]+)?$/,resolve:t=>parseFloat(t),stringify:rt}],fs={default:!0,tag:"",test:/^/,resolve(t,e){return e(`Unresolved plain scalar ${JSON.stringify(t)}`),t}},us=[Ae,Oe].concat(cs,fs);function ln(t,e,n){let{replacer:s}=n,i=new B(t);i.tag="tag:yaml.org,2002:pairs";let r=0;if(e&&Symbol.iterator in Object(e))for(let o of e){typeof s=="function"&&(o=s.call(e,String(r++),o));let c,a;if(Array.isArray(o))if(o.length===2)c=o[0],a=o[1];else throw new TypeError(`Expected [key, value] tuple: ${o}`);else if(o&&o instanceof Object){let l=Object.keys(o);if(l.length===1)c=l[0],a=o[c];else throw new TypeError(`Expected tuple with one key, not ${l.length} keys`)}else c=o;i.items.push(Le(c,a,n))}return i}var At=class t extends B{constructor(){super(),this.add=j.prototype.add.bind(this),this.delete=j.prototype.delete.bind(this),this.get=j.prototype.get.bind(this),this.has=j.prototype.has.bind(this),this.set=j.prototype.set.bind(this),this.tag=t.tag}toJSON(e,n){if(!n)return super.toJSON(e);let s=new Map;n?.onCreate&&n.onCreate(s);for(let i of this.items){let r,o;if(k(i)?(r=C(i.key,"",n),o=C(i.value,r,n)):r=C(i,"",n),s.has(r))throw new Error("Ordered maps must not include duplicate keys");s.set(r,o)}return s}static from(e,n,s){let i=ln(e,n,s),r=new this;return r.items=i.items,r}};At.tag="tag:yaml.org,2002:omap";var Ot=class t extends j{constructor(e){super(e),this.tag=t.tag}add(e){let n;k(e)?n=e:e&&typeof e=="object"&&"key"in e&&"value"in e&&e.value===null?n=new M(e.key,null):n=new M(e,null),re(this.items,n.key)||this.items.push(n)}get(e,n){let s=re(this.items,e);return!n&&k(s)?S(s.key)?s.key.value:s.key:s}set(e,n){if(typeof n!="boolean")throw new Error(`Expected boolean value for set(key, value) in a YAML set, not ${typeof n}`);let s=re(this.items,e);s&&!n?this.items.splice(this.items.indexOf(s),1):!s&&n&&this.items.push(new M(e))}toJSON(e,n){return super.toJSON(e,n,Set)}toString(e,n,s){if(!e)return JSON.stringify(this);if(this.hasAllNullValues(!0))return super.toString(Object.assign({},e,{allNullValues:!0}),n,s);throw new Error("Set items must all have null values")}static from(e,n,s){let{replacer:i}=s,r=new this(e);if(n&&Symbol.iterator in Object(n))for(let o of n)typeof i=="function"&&(o=i.call(n,o,o)),r.items.push(Le(o,null,s));return r}};Ot.tag="tag:yaml.org,2002:set";function ps(t,e){let n=t[0],s=n==="-"||n==="+"?t.substring(1):t,i=o=>e?BigInt(o):Number(o),r=s.replace(/_/g,"").split(":").reduce((o,c)=>o*i(60)+i(c),i(0));return n==="-"?i(-1)*r:r}var It={identify:t=>t instanceof Date,default:!0,tag:"tag:yaml.org,2002:timestamp",test:RegExp("^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})(?:(?:t|T|[ \\t]+)([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?)?$"),resolve(t){let e=t.match(It.test);if(!e)throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");let[,n,s,i,r,o,c]=e.map(Number),a=e[7]?Number((e[7]+"00").substr(1,3)):0,l=Date.UTC(n,s-1,i,r||0,o||0,c||0,a),m=e[8];if(m&&m!=="Z"){let f=ps(m,!1);Math.abs(f)<30&&(f*=60),l-=6e4*f}return new Date(l)},stringify:({value:t})=>t?.toISOString().replace(/(T00:00:00)?\.000Z$/,"")??""};var Mt=Symbol("break visit"),Es=Symbol("skip children"),fn=Symbol("remove item");function me(t,e){"type"in t&&t.type==="document"&&(t={start:t.start,value:t.value}),un(Object.freeze([]),t,e)}me.BREAK=Mt;me.SKIP=Es;me.REMOVE=fn;me.itemAtPath=(t,e)=>{let n=t;for(let[s,i]of e){let r=n?.[s];if(r&&"items"in r)n=r.items[i];else return}return n};me.parentCollection=(t,e)=>{let n=me.itemAtPath(t,e.slice(0,-1)),s=e[e.length-1][0],i=n?.[s];if(i&&"items"in i)return i;throw new Error("Parent collection not found")};function un(t,e,n){let s=n(e,t);if(typeof s=="symbol")return s;for(let i of["key","value"]){let r=e[i];if(r&&"items"in r){for(let o=0;o<r.items.length;++o){let c=un(Object.freeze(t.concat([[i,o]])),r.items[o],n);if(typeof c=="number")o=c-1;else{if(c===Mt)return Mt;c===fn&&(r.items.splice(o,1),o-=1)}}typeof s=="function"&&i==="key"&&(s=s(e,t))}}return typeof s=="function"?s(e,t):s}var zc=new Set("0123456789ABCDEFabcdef"),Qc=new Set("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-#;/?:@&=+$_.!~*'()"),Xc=new Set(",[]{}"),Zc=new Set(` ,[]{}
|
|
53
|
+
\r `);var oe="log";function dn(t){return t.trim().replace(/^#+/,"").toLowerCase().replace(/\s+/g,"-").replace(/[^\p{L}\p{N}_-]/gu,"")}var xs={p:"project",project:"project",projects:"project",t:"tag",tag:"tag",tags:"tag",type:"type",author:"author",by:"author",person:"author",who:"author",after:"after",from:"after",since:"after",before:"before",to:"before",until:"before",on:"on",date:"on",amount:"amount",has:"has"},Ms=t=>xs[t.toLowerCase()]??t.toLowerCase();function lt(t){let e=[];for(let n of t.matchAll(/(?:([A-Za-z_][\w-]*):)?(?:"([^"]*)"|(\S+))/g)){let s=n[1],i=(n[2]??n[3]??"").trim();if(s&&i.startsWith("//")){e.push({value:`${s}:${i}`});continue}i&&(!s&&/^#[\p{L}\p{N}]/u.test(i)?e.push({key:"tag",value:i.slice(1)}):e.push(s?{key:Ms(s),value:i}:{value:i}))}return e}function ct(t){return t.map(e=>{let n=/[\s"]/.test(e.value)?`"${e.value.replace(/"/g,"")}"`:e.value;return e.key?`${e.key}:${n}`:n}).join(" ")}function Ds(t){let e={terms:[],projects:[],tags:[],types:[],authors:[],amounts:[],has:[],fields:[]};for(let{key:n,value:s}of lt(t))switch(n){case void 0:e.terms.push(s.toLowerCase());break;case"project":e.projects.push(Yt(s));break;case"tag":e.tags.push(dn(s));break;case"type":e.types.push(s.toLowerCase());break;case"author":e.authors.push(s.toLowerCase());break;case"after":e.after=hn(s)??e.after;break;case"before":e.before=gn(s)??e.before;break;case"on":e.after=hn(s)??e.after,e.before=gn(s)??e.before;break;case"amount":{let i=/^(>=|<=|>|<|=)?\s*[$€£¥]?([\d,]*\.?\d+)$/.exec(s);i&&e.amounts.push({op:i[1]??"=",value:Number(i[2].replace(/,/g,""))});break}case"has":e.has.push(s.toLowerCase());break;default:e.fields.push({key:n,value:s.toLowerCase()})}return e}var mn=t=>t!==null&&typeof t=="object"?JSON.stringify(t):String(t),Ps=new Set(["expense","purchase","payment"]),at=class{entries;#e;#t=new WeakMap;constructor(e,n={}){this.entries=e,this.#e=n}search(e){if(!e.trim())return this.entries;let n=Ds(e);return this.entries.filter(s=>this.matches(s,n))}matches(e,n){if(n.projects.length&&!n.projects.some(r=>e.projects.includes(r))||n.tags.length&&!n.tags.some(r=>e.tags.includes(r))||n.types.length&&!n.types.includes(e.type)||n.authors.length&&!n.authors.some(r=>e.author.toLowerCase().includes(r)))return!1;let s=Date.parse(e.occurred);if(n.after!==void 0&&s<n.after||n.before!==void 0&&s>n.before||n.amounts.length&&!(e.amount&&n.amounts.every(r=>_s(e.amount.value,r)))||!n.has.every(r=>Bs(e,r)))return!1;for(let r of n.fields){let o=e.data[r.key];if(o==null||!mn(o).toLowerCase().includes(r.value))return!1}if(!n.terms.length)return!0;let i=this.#n(e);return n.terms.every(r=>i.includes(r))}#n(e){let n=this.#t.get(e);return n===void 0&&(n=[e.body,e.author,e.type,this.#e.typeLabels?.get(e.type)??"",...e.tags,...e.projects.flatMap(s=>[s,this.#e.projectNames?.get(s)??""]),...e.attachments.map(s=>s.name),e.amount?`${e.amount.value} ${e.amount.currency}`:"",...Object.values(e.data).map(mn),e.source?.adapter??""].join(`
|
|
54
|
+
`).toLowerCase(),this.#t.set(e,n)),n}};function _s(t,e){switch(e.op){case">":return t>e.value;case">=":return t>=e.value;case"<":return t<e.value;case"<=":return t<=e.value;default:return t===e.value}}function Bs(t,e){let n=t.attachments;switch(e){case"attachment":case"attachments":case"file":case"files":return n.length>0;case"photo":case"photos":case"image":case"images":return n.some(s=>s.type.startsWith("image/"));case"receipt":case"receipts":return n.some(s=>s.type==="application/pdf"||/receipt/i.test(s.name))||n.length>0&&Ps.has(t.type);case"pdf":case"document":return n.some(s=>s.type==="application/pdf");case"amount":case"money":return!!t.amount;default:{let s=t.data[e];return s!=null&&s!==""&&s!==!1}}}function yn(t){let e=/^(\d{4})(?:-(\d{2}))?(?:-(\d{2}))?$/.exec(t);return e?[Number(e[1]),e[2]?Number(e[2])-1:0,e[3]?Number(e[3]):null]:null}function hn(t){let e=yn(t);return e?new Date(e[0],e[1],e[2]??1).getTime():void 0}function gn(t){let e=yn(t);return e?(/^\d{4}$/.test(t)?new Date(e[0]+1,0,1):e[2]===null?new Date(e[0],e[1]+1,1):new Date(e[0],e[1],e[2]+1)).getTime()-1:void 0}var Ie=(t,e,n,s,i,r)=>({id:t,label:e,icon:n,amount:s,fields:i,description:r,builtin:!0}),ft=(t,e,n={})=>({key:t,label:e,kind:"text",...n}),bn=(t,e)=>({key:t,label:e,kind:"date"}),ut=(t,e,n)=>({key:t,label:e,kind:"select",options:n}),Rs=[Ie(oe,"Log","📝","optional",[],"Something happened."),Ie("expense","Expense","🧾","expected",[ft("vendor","Paid to"),ft("category","Category"),ut("method","Method",["card","cash","check","transfer","other"])],"Money spent, usually with a receipt."),Ie("maintenance","Maintenance","🔧","optional",[ft("asset","Asset"),ft("vendor","Done by"),bn("next_due","Next due"),bn("warranty_until","Warranty until")],"Service, repair or upkeep."),Ie("decision","Decision","⚖️","none",[ut("status","Status",["decided","proposed","reversed"]),{key:"alternatives",label:"Alternatives considered",kind:"longtext"}],"A choice that was made, and why."),Ie("milestone","Milestone","🏁","none",[],"A notable moment."),Ie("issue","Issue","⚠️","optional",[ut("severity","Severity",["low","medium","high"]),ut("status","Status",["open","resolved"])],"A problem that was noticed.")];function Dt(t=[]){let e=new Map(Rs.map(n=>[n.id,n]));for(let n of t)e.set(n.id,n);return e}function he(t,e){return t.get(e)??{...t.get(oe),id:e,label:e,icon:"•",builtin:!1}}function wn(t,e){let n={};for(let[s,i]of Object.entries(e)){let r=t.fields.find(o=>o.key===s);if(!(i===""||i==null)){if(!r){n[s]=i;continue}switch(r.kind){case"number":{let o=typeof i=="number"?i:Number(String(i).replace(/,/g,""));n[s]=Number.isFinite(o)?o:i;break}case"boolean":n[s]=i===!0||i==="true"||i==="on"||i==="yes";break;default:n[s]=typeof i=="string"?i.trim():i}}}return n}var x={saved:"Saved.",edited:"Changes saved. Earlier versions are in History.",deleted:"Deleted. It's still in History.",confirmDelete:"Delete this event? It won't show in your timeline, but it stays in History.",confirmDiscard:"Discard what you wrote?",badAmount:"That amount doesn't look right. Try 1850 or $1,850.",stopped:"GitRoll has stopped. Start it again from your terminal with: gitroll",signedOut:"For your privacy, open GitRoll from the link shown in your terminal.",empty:"Nothing logged yet.",noMatches:"Nothing found.",notBackedUp:"Not backed up yet",newProject:"Project name",askPlaceholder:"Ask a question, like: When was the AC last serviced?"},Fs=1e4,y=(t,e=document)=>e.querySelector(t),we=y("#view"),ye=y("#composer"),P=null,Pt=null,Sn="",G=Dt(),U=null,ae=null,R=null,be=null,ge="ok",I=()=>{if(!P)throw new Error(x.stopped);return P};function u(t){return String(t??"").replace(/[&<>"']/g,e=>`&#${e.charCodeAt(0)};`)}var Se=t=>t instanceof Error?t.message:String(t),Ce=(t,e,n)=>`${t} ${t===1?e:n}`,Ks=t=>typeof t=="string"&&/^https?:\/\//i.test(t);function Re(t,e){let n=t;return!n||n._html===e?!1:(n.innerHTML=e,n._html=e,gt(n),!0)}var kn=0;function X(t,e=!1){let n=y("#toast");n.textContent=t,n.className=`show${e?" error":""}`,clearTimeout(kn),kn=window.setTimeout(()=>n.className="",e?8e3:3e3)}var Us=t=>new Date(t).toLocaleTimeString([],{hour:"numeric",minute:"2-digit"});function Nn(t){let e=new Date,n=new Date;return n.setDate(e.getDate()-1),t.toDateString()===e.toDateString()?"Today":t.toDateString()===n.toDateString()?"Yesterday":t.toLocaleDateString([],{weekday:"long",month:"long",day:"numeric",year:t.getFullYear()===e.getFullYear()?void 0:"numeric"})}function Ln(t){try{return new Intl.NumberFormat([],{style:"currency",currency:t.currency}).format(t.value)}catch{return`${t.value} ${t.currency}`}}function An(t){return t?t<1024?`${t} B`:t<1048576?`${Math.round(t/1024)} KB`:`${(t/1048576).toFixed(1)} MB`:""}var Fe=t=>t.type.startsWith("image/")&&!t.type.includes("svg")&&!t.type.includes("heic"),On=t=>Fe(t)?"Photo":t.type==="application/pdf"?"PDF":"File",Rt=t=>I().projects().find(e=>e.slug===t)?.name??t,Ft=t=>`#/?q=${encodeURIComponent(ct(t))}`;function qs(t){let e=new Date(t),n=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())}T${n(e.getHours())}:${n(e.getMinutes())}`}function In(t){return t.trim()?t.trim().split(/\n{2,}/).map(e=>`<p>${Hs(u(e)).replace(/\n/g,"<br>")}</p>`).join(""):""}function Hs(t){return t.replace(/https?:\/\/[^\s<]+[^\s<.,;:!?)]/g,e=>`<a href="${e}" target="_blank" rel="noopener noreferrer">${e}</a>`).replace(/(^|[\s(>])#(\p{L}[\p{L}\p{N}_-]*)/gu,(e,n,s)=>`${n}<a class="tag" href="${Ft([{key:"tag",value:s.toLowerCase()}])}" data-filter-key="tag" data-filter-value="${u(s.toLowerCase())}">#${s}</a>`)}function pt(t,e,n,s=""){return`<a class="${s}" href="${Ft([{key:t,value:e}])}" data-filter-key="${u(t)}" data-filter-value="${u(e)}">${n}</a>`}function gt(t){if(!P)return;let e=new Map(P.entries().flatMap(n=>n.attachments.map(s=>[s.hash,s])));for(let n of t.querySelectorAll("[data-att]")){let s=e.get(n.dataset.att);if(delete n.dataset.att,!s)continue;let i=P.attachmentUrl(s);n instanceof HTMLImageElement?(n.src=i,n.addEventListener("error",()=>n.classList.add("broken"),{once:!0})):n instanceof HTMLAnchorElement&&(n.href=i)}}function Cn(){let t=I();return(!Pt||Sn!==t.version())&&(G=Dt(t.types()),Pt=new at(t.entries(),{projectNames:new Map(t.projects().map(e=>[e.slug,e.name])),typeLabels:new Map([...G.values()].map(e=>[e.id,e.label]))}),Sn=t.version()),Pt}var jn=()=>new Set(I().entries().map(t=>t.author)).size>1;function xn(t){document.body.classList.remove("connected"),we.innerHTML=`
|
|
55
|
+
<section class="notice">
|
|
56
|
+
<h1>GitRoll</h1>
|
|
57
|
+
<p>${t==="signed-out"?u(x.signedOut):"GitRoll isn't running."}</p>
|
|
58
|
+
${t==="stopped"?'<p class="muted">Start it from your terminal:</p><pre class="cmd">gitroll</pre>':""}
|
|
59
|
+
</section>`}function Mn(t,e={}){if(window.top!==window.self){document.body.textContent="For your security, GitRoll can't be shown inside another page.";return}ai(),P=t;let n=y("#sync").childNodes[0];e.syncLabel&&n&&(n.textContent=e.syncLabel),document.body.classList.add("connected"),Ke(),Kt()}function Ke(){let t=I().info(),e=t.sync;y("#roll-name").textContent=t.name,document.title=`${t.name} · GitRoll`;let n=y("#sync-count");n.hidden=!e.ahead,n.textContent=String(e.ahead),y("#sync").title=e.remote?e.ahead?`${Ce(e.ahead,"change","changes")} to sync`:"Everything is synced":`${x.notBackedUp}. Your events are saved on this computer.`}function Kt(){if(!P)return;U=null,ae=null,R=null;let t=location.hash||"#/";for(let e of document.querySelectorAll("[data-nav]"))e.dataset.nav===(t.startsWith("#/projects")?"projects":"timeline")?e.setAttribute("aria-current","page"):e.removeAttribute("aria-current");try{Cn();let e;(e=t.match(/^#\/?(?:\?q=(.*))?$/))?Vs(decodeURIComponent(e[1]??"")):t==="#/projects"?Xs():(e=t.match(/^#\/entry\/([^/?]+)$/))?Zs(decodeURIComponent(e[1])):location.replace("#/")}catch(e){we.innerHTML=`<p class="banner error">${u(Se(e))}</p>`}}function Ys(){let t=I().info(),e=[];ge!=="ok"&&e.push(`<p class="banner error">${u(ge==="signed-out"?x.signedOut:x.stopped)}</p>`);for(let n of t.warnings)e.push(`<p class="banner">${u(n)}</p>`);return be&&!be.ok&&be.code!=="no-remote"&&e.push(`<p class="banner">${u(be.message)} <button class="link" data-action="sync">Try again</button></p>`),t.problems.length&&e.push(`<details class="banner"><summary>${Ce(t.problems.length,"file","files")} in this Roll couldn't be read</summary>
|
|
60
|
+
<ul>${t.problems.map(n=>`<li><code>${u(n.path)}</code>: ${u(n.error)}</li>`).join("")}</ul></details>`),e.join("")}function Vs(t){let e=lt(t),n=e.filter(l=>l.key),s=I().info().ai.enabled;we.innerHTML=`
|
|
61
|
+
<section class="find" role="search">
|
|
62
|
+
<div class="searchbox">
|
|
63
|
+
<input id="q" type="search" placeholder="Search" autocomplete="off" spellcheck="false" enterkeyhint="search" aria-label="Search">
|
|
64
|
+
${s?`<button type="button" class="secondary" data-action="ask" title="${u(x.askPlaceholder)}">Ask</button>`:""}
|
|
65
|
+
</div>
|
|
66
|
+
<div class="chips" id="quick"></div>
|
|
67
|
+
</section>
|
|
68
|
+
<div id="answer"></div>
|
|
69
|
+
<div id="banners"></div>
|
|
70
|
+
<div id="summary"></div>
|
|
71
|
+
<div id="list"></div>`;let i=y("#q");i.value=ct(e.filter(l=>!l.key));let r=(l,m,f)=>l.key===m&&l.value.toLowerCase()===f.toLowerCase(),o=()=>[ct(n),i.value.trim()].filter(Boolean).join(" "),c=()=>{let l=o();history.replaceState(null,"",l?`#/?q=${encodeURIComponent(l)}`:"#/"),U?.()};ae={toggle(l,m){let f=n.findIndex(d=>r(d,l,m));f>=0?n.splice(f,1):n.push({key:l,value:m}),c()},dates(l){let m=n.find(f=>f.key==="after")?.value;n=n.filter(f=>!["after","before","on"].includes(f.key)),l&&l!==m&&n.push({key:"after",value:l}),c()},clear(){n=[],i.value="",c()},query:()=>i.value.trim()},U=()=>{let l=o(),m=Cn().search(l);Re(y("#banners"),Ys()),Re(y("#quick"),Js(n)),Re(y("#summary"),Gs(m,!!l)),Re(y("#list"),m.length||l?Dn(m,`<p>${x.noMatches}</p>${l?'<button class="link" data-action="clear-filters">Show everything</button>':""}`):`<div class="empty"><p class="big">What happened?</p><p class="muted">${x.empty}</p><button class="primary" data-action="new">Log something</button></div>`)};let a=0;i.addEventListener("input",()=>{clearTimeout(a),a=window.setTimeout(c,80)}),i.addEventListener("keydown",l=>{l.key==="Escape"&&i.value&&(i.value="",c())}),U()}function Js(t){let e=new Date,n=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-01`,s=`${e.getFullYear()}-01-01`,i=t.find(a=>a.key==="after")?.value,r=(a,l,m)=>`<button type="button" class="chip${l?" on":""}" aria-pressed="${l}" ${m}>${a}</button>`,o=[r("This month",i===n,`data-date-after="${n}"`),r("This year",i===s,`data-date-after="${s}"`),r("With files",t.some(a=>a.key==="has"&&a.value==="attachment"),'data-filter-key="has" data-filter-value="attachment"')],c=t.filter(a=>!(a.key==="has"&&a.value==="attachment")&&!(a.key==="after"&&(a.value===n||a.value===s))).map(a=>`<button type="button" class="chip on" data-filter-key="${u(a.key)}" data-filter-value="${u(a.value)}" aria-label="Remove ${u(vn(a))}">${u(vn(a))} <span aria-hidden="true">×</span></button>`);return[...o,...c].join("")}function vn(t){switch(t.key){case"project":return Rt(t.value);case"tag":return`#${t.value}`;case"type":return he(G,t.value).label;case"author":return t.value;case"after":return`Since ${t.value}`;case"before":return`Until ${t.value}`;case"on":return t.value;case"has":return`With ${t.value}`;default:return`${t.key}: ${t.value}`}}function Gs(t,e){if(!e)return"";let n=new Map;for(let i of t)i.amount&&n.set(i.amount.currency,(n.get(i.amount.currency)??0)+i.amount.value);let s=[Ce(t.length,"event","events")];for(let[i,r]of n)s.push(`${Ln({value:r,currency:i})} total`);return`<p class="summary">${s.map(u).join(" · ")}</p>`}function Dn(t,e){if(!t.length)return`<div class="empty">${e}</div>`;let n=jn(),s="",i="";for(let r of t){let o=new Date(r.occurred);o.toDateString()!==i&&(s+=`${i?"</section>":""}<section class="day"><h2>${u(Nn(o))}</h2>`,i=o.toDateString()),s+=zs(r,n)}return`${s}</section>`}function Pn(t,e){let n=[];for(let s of e.fields){let i=t.data[s.key];i!=null&&i!==""&&i!==!1&&n.push([u(s.label),Ws(s,i)])}for(let[s,i]of Object.entries(t.data))e.fields.some(r=>r.key===s)||i==null||i===""||n.push([u(s.replace(/_/g," ")),u(typeof i=="object"?JSON.stringify(i):String(i))]);return n}function Ws(t,e){if(t.kind==="boolean")return e===!0?"Yes":"No";if(t.kind==="date"){let n=new Date(`${String(e).slice(0,10)}T12:00:00`);return u(Number.isNaN(n.getTime())?String(e):n.toLocaleDateString([],{dateStyle:"medium"}))}return t.kind==="url"&&Ks(e)?`<a href="${u(e)}" target="_blank" rel="noopener noreferrer">${u(e)}</a>`:u(typeof e=="object"?JSON.stringify(e):String(e))}function _n(t,e){let n=[];for(let s of t.projects)n.push(pt("project",s,u(Rt(s)),"project"));return t.type!==oe&&n.push(pt("type",t.type,u(e.label),"kind")),t.amount&&n.push(`<span class="amount">${u(Ln(t.amount))}</span>`),n.length?`<div class="labels">${n.join("")}</div>`:""}function Bn(t,e,n=!0){let s=[];n&&t.attachments.length&&s.push(`<span>${Ce(t.attachments.length,"file","files")}</span>`);for(let i of t.tags)s.push(pt("tag",i,`#${u(i)}`,"tag"));return e&&t.author&&s.push(pt("author",t.author,u(t.author),"author")),s.length?`<div class="foot">${s.join("")}</div>`:""}function zs(t,e){let n=he(G,t.type),s=t.attachments.filter(Fe),i=Pn(t,n).slice(0,2);return`
|
|
72
|
+
<article class="entry" data-id="${u(t.id)}" tabindex="0">
|
|
73
|
+
<time class="when" datetime="${u(t.occurred)}">${Us(t.occurred)}</time>
|
|
74
|
+
<div class="content">
|
|
75
|
+
${_n(t,n)}
|
|
76
|
+
<div class="body">${In(t.body)}</div>
|
|
77
|
+
${i.length?`<div class="fields">${i.map(([r,o])=>`<span><small>${r}</small> ${o}</span>`).join("")}</div>`:""}
|
|
78
|
+
${s.length?`<div class="thumbs">${s.slice(0,4).map(r=>`<img data-att="${u(r.hash)}" alt="${u(r.name)}" loading="lazy">`).join("")}${s.length>4?`<span class="more">+${s.length-4}</span>`:""}</div>`:""}
|
|
79
|
+
${Bn(t,e)}
|
|
80
|
+
</div>
|
|
81
|
+
</article>`}async function Qs(){let t=ae?.query()??"",e=y("#answer");if(!t){y("#q").placeholder=x.askPlaceholder,y("#q").focus();return}e.innerHTML='<div class="answer muted">Thinking…</div>';try{let{answer:n,sources:s}=await I().ask(t),i=new Map(s.map(c=>[c.short,c.id])),r=u(n).replace(/\[([0-9a-f]{8})\]/g,(c,a)=>i.has(a)?`<a href="#/entry/${encodeURIComponent(i.get(a))}" class="cite">view</a>`:""),o=I().entries().filter(c=>s.some(a=>a.id===c.id));e.innerHTML=`
|
|
82
|
+
<div class="answer">
|
|
83
|
+
<p>${r.replace(/\n/g,"<br>")}</p>
|
|
84
|
+
${o.length?`<p class="muted small">Based on ${Ce(o.length,"event","events")} below. Answers can be wrong; check the events.</p>${Dn(o,"")}`:'<p class="muted small">No events were cited. Answers can be wrong.</p>'}
|
|
85
|
+
<button class="link" data-action="close-answer">Close</button>
|
|
86
|
+
</div>`,gt(e)}catch(n){e.innerHTML=`<p class="banner error">${u(Se(n))}</p>`}}function Xs(){we.innerHTML='<div class="page-head"><h1>Projects</h1><button class="secondary" data-action="new-project">New project</button></div><div id="list"></div>',U=()=>{let t=I().entries(),e=I().projects(),n=[...new Set(t.flatMap(i=>i.projects))].filter(i=>!e.some(r=>r.slug===i)).map(i=>({slug:i,name:i})),s=[...e,...n].map(i=>{let r=t.filter(o=>o.projects.includes(i.slug));return{...i,count:r.length,last:r[0]?.occurred}});Re(y("#list"),s.length?`<ul class="list">${s.map(i=>`<li><a class="row" href="${Ft([{key:"project",value:i.slug}])}"><strong>${u(i.name)}</strong><span>${Ce(i.count,"event","events")}${i.last?` · ${u(Nn(new Date(i.last)))}`:""}</span></a></li>`).join("")}</ul>`:'<div class="empty"><p class="muted">Projects group related events, like House or Car.</p><button class="primary" data-action="new-project">New project</button></div>')},U()}function Zs(t){U=()=>{let e=I().entries().find(i=>i.id===t);if(!e){R=null,we.innerHTML=`<button class="link back" data-action="back">← Back</button><div class="empty"><p class="muted">This event was deleted. It's still in History.</p></div>`;return}if(R&&JSON.stringify(R)===JSON.stringify(e))return;R=e;let n=he(G,e.type),s=Pn(e,n);we.innerHTML=`
|
|
87
|
+
<button class="link back" data-action="back">← Back</button>
|
|
88
|
+
<article class="detail">
|
|
89
|
+
<time datetime="${u(e.occurred)}">${u(new Date(e.occurred).toLocaleString([],{dateStyle:"full",timeStyle:"short"}))}</time>
|
|
90
|
+
${_n(e,n)}
|
|
91
|
+
<div class="body large">${In(e.body)}</div>
|
|
92
|
+
${s.length?`<dl class="facts">${s.map(([i,r])=>`<dt>${i}</dt><dd>${r}</dd>`).join("")}</dl>`:""}
|
|
93
|
+
${e.attachments.length?`<div class="attachments">${e.attachments.map(ei).join("")}</div>`:""}
|
|
94
|
+
${Bn(e,jn(),!1)}
|
|
95
|
+
<div class="actions">
|
|
96
|
+
<button class="secondary" data-action="edit">Edit</button>
|
|
97
|
+
<button class="secondary" data-action="history">History</button>
|
|
98
|
+
<button class="secondary danger" data-action="delete">Delete</button>
|
|
99
|
+
</div>
|
|
100
|
+
<details class="more-info">
|
|
101
|
+
<summary>Details</summary>
|
|
102
|
+
<dl class="facts">
|
|
103
|
+
<dt>Logged by</dt><dd>${u(e.author||"Unknown")}</dd>
|
|
104
|
+
<dt>Logged on</dt><dd>${u(new Date(e.created).toLocaleString())}</dd>
|
|
105
|
+
${e.source?`<dt>Imported from</dt><dd>${u(e.source.adapter)}</dd>`:""}
|
|
106
|
+
<dt>File</dt><dd><code>${u(e.path)}</code></dd>
|
|
107
|
+
</dl>
|
|
108
|
+
</details>
|
|
109
|
+
<section id="history" class="history"></section>
|
|
110
|
+
</article>`,gt(we)},U()}function ei(t){if(Fe(t))return`<a class="att img" data-att="${u(t.hash)}" target="_blank" rel="noopener noreferrer"><img data-att="${u(t.hash)}" alt="${u(t.name)}"></a>`;let e=t.type==="application/pdf"||/^(image|video|audio)\//.test(t.type)||t.type==="text/plain";return`<a class="att file" data-att="${u(t.hash)}" ${e?'target="_blank" rel="noopener noreferrer"':`download="${u(t.name)}"`}>
|
|
111
|
+
<span class="kind">${On(t)}</span><span class="fname">${u(t.name)}</span><small>${u(An(t.size))}</small></a>`}async function ti(t){let e=y("#history");e.innerHTML='<p class="muted">Loading…</p>';try{let n=await I().history(t.id);e.innerHTML=`<h2>History</h2><ol class="revs">${n.map((s,i)=>{let r=i===n.length-1;return`<li><div class="rev-head"><strong>${r?"Logged":"Edited"}</strong> ${u(new Date(s.date).toLocaleString([],{dateStyle:"medium",timeStyle:"short"}))} · ${u(s.author)}</div>
|
|
112
|
+
${r?"":`<pre class="diff">${ni(s.patch)}</pre>`}</li>`}).join("")}</ol>`}catch(n){e.innerHTML=`<p class="banner error">${u(Se(n))}</p>`}}function ni(t){return t.split(`
|
|
113
|
+
`).filter(e=>!/^(diff --git|index |--- |\+\+\+ |\\ No newline|new file mode|deleted file mode|similarity index|rename (from|to) |@@)/.test(e)).filter(e=>/^[+-]/.test(e)).map(e=>`<span class="${e.startsWith("+")?"add":"del"}">${u(e.slice(1))||" "}</span>`).join(`
|
|
114
|
+
`)}var g={editing:null,type:oe,data:{},files:[],removed:new Set,projects:new Set,initialWhen:""},dt=new Map;function Tn(){let t=(location.hash||"").match(/^#\/?\?q=(.*)$/);if(!t)return;let e=lt(decodeURIComponent(t[1])).filter(n=>n.key==="project");return e.length===1?e[0].value:void 0}function _t(t={}){let e=t.entry??null;g.editing=e,g.type=e?.type??oe,g.data={...e?.data??{}},g.files=[],g.removed=new Set,g.projects=new Set(e?e.projects:t.project?[t.project]:[]),g.initialWhen=e?qs(e.occurred):"",y("#c-title").textContent=e?"Edit":"What happened?",y("#c-text").value=e?.body??"",y("#c-tags").value=e?e.tags.join(", "):"",y("#c-amount").value=e?.amount?`${e.amount.value}${e.amount.currency!=="USD"?` ${e.amount.currency}`:""}`:"",y("#c-when").value=g.initialWhen,y("#c-more").open=!!e&&(e.type!==oe||e.projects.length>0||!!e.amount||e.tags.length>0),Fn(),Kn(),mt(),ht(),ye.showModal(),y("#c-text").focus()}function Rn(){for(let t of dt.values())URL.revokeObjectURL(t);dt.clear(),ye.close()}var $n=()=>!g.editing&&(y("#c-text").value.trim()!==""||g.files.length>0);function Fn(){y("#c-types").innerHTML=[...G.values()].map(t=>`<button type="button" class="chip${g.type===t.id?" on":""}" data-type-pick="${u(t.id)}" aria-pressed="${g.type===t.id}">${u(t.label)}</button>`).join("")}function Kn(){let t=he(G,g.type);y("#c-fields").innerHTML=t.fields.map(e=>si(e,g.data[e.key])).join("")}function si(t,e){let n=e==null?"":String(e),s=`data-field="${u(t.key)}"${t.required?" required":""}`,i=u(t.label);switch(t.kind){case"longtext":return`<label class="wide">${i}<textarea ${s} rows="2">${u(n)}</textarea></label>`;case"select":return`<label>${i}<select ${s}><option value=""></option>${(t.options??[]).map(r=>`<option${r===n?" selected":""}>${u(r)}</option>`).join("")}</select></label>`;case"boolean":return`<label class="check"><input type="checkbox" ${s}${e===!0?" checked":""}> ${i}</label>`;case"date":return`<label>${i}<input type="date" ${s} value="${u(n.slice(0,10))}"></label>`;case"number":return`<label>${i}<input type="number" step="any" ${s} value="${u(n)}"></label>`;case"url":return`<label>${i}<input type="url" ${s} value="${u(n)}" placeholder="https://"></label>`;default:return`<label>${i}<input ${s} value="${u(n)}"></label>`}}function ii(t){let e=t.defaults;if(!e||g.editing)return;let n=y("#c-text");e.text&&!n.value.trim()&&(n.value=e.text);let s=y("#c-tags");e.tags?.length&&!s.value.trim()&&(s.value=e.tags.join(", "));let i=y("#c-amount");e.amount&&!i.value.trim()&&(i.value=String(e.amount.value));for(let r of e.projects??[])g.projects.add(r);for(let[r,o]of Object.entries(e.data??{}))(g.data[r]==null||g.data[r]==="")&&(g.data[r]=o);mt()}function Un(){for(let t of document.querySelectorAll("#c-fields [data-field]"))g.data[t.dataset.field]=t.type==="checkbox"?t.checked?!0:void 0:t.value}function mt(){let t=new Set([...I().projects().map(e=>e.slug),...g.projects]);y("#c-projects").innerHTML=[...t].map(e=>`<button type="button" class="chip${g.projects.has(e)?" on":""}" data-project-toggle="${u(e)}" aria-pressed="${g.projects.has(e)}">${u(Rt(e))}</button>`).join("")+'<button type="button" class="chip add" data-action="composer-new-project">New project</button>'}function Bt(t){let e=I().info().maxAttachmentBytes;for(let n of t)n.size>e?X(`${n.name} is too large. Files can be up to ${Math.round(e/1048576)} MB.`,!0):g.files.push(n);ht()}function ht(){let t=(g.editing?.attachments??[]).map(s=>{let i=g.removed.has(s.hash);return`<div class="file${i?" removed":""}">${Fe(s)?`<img data-att="${u(s.hash)}" alt="">`:`<span class="kind">${On(s)}</span>`}
|
|
115
|
+
<span class="fname">${u(s.name)}</span>
|
|
116
|
+
<button type="button" class="link" data-remove-existing="${u(s.hash)}">${i?"Keep":"Remove"}</button></div>`}),e=g.files.map((s,i)=>{let r="";return Fe(s)&&(r=dt.get(s)??URL.createObjectURL(s),dt.set(s,r)),`<div class="file">${r?`<img src="${r}" alt="">`:'<span class="kind">File</span>'}
|
|
117
|
+
<span class="fname">${u(s.name||"Pasted file")}</span><small>${u(An(s.size))}</small>
|
|
118
|
+
<button type="button" class="link" data-remove-new="${i}">Remove</button></div>`}),n=y("#c-files");n.innerHTML=[...t,...e].join(""),gt(n)}async function ri(t){t.preventDefault();let e=y("#c-submit");if(e.disabled)return;Un();let n=he(G,g.type),s=y("#c-text").value,i=y("#c-tags").value.split(/[,\s]+/).map(f=>f.replace(/^#/,"")).filter(Boolean),r=y("#c-amount").value.trim(),o=r?Vt(r):null;if(r&&!o){y("#c-more").open=!0,X(x.badAmount,!0);return}let c=new Set([...G.values()].flatMap(f=>f.fields.map(d=>d.key))),a=wn(n,Object.fromEntries(Object.entries(g.data).filter(([f])=>n.fields.some(d=>d.key===f)||!c.has(f)))),l=y("#c-when").value,m=g.editing;e.disabled=!0,e.textContent="Saving…";try{let f;if(m){let d={text:s,type:g.type,data:a,tags:i,projects:[...g.projects],amount:o,removeAttachments:[...g.removed]};l!==g.initialWhen&&(d.occurred=l?yt(new Date(l)):""),{notices:f}=await I().updateEntry(m.id,d,g.files,m)}else({notices:f}=await I().addEntry({text:s,type:g.type,data:a,tags:i,projects:[...g.projects],amount:o??void 0,occurred:l?yt(new Date(l)):void 0},g.files));Rn(),X([m?x.edited:x.saved,...f].join(" ")),Ke(),Kt()}catch(f){X(Se(f),!0)}finally{e.disabled=!1,e.textContent="Save"}}async function oi(){let t=y("#sync");if(!t.disabled){t.disabled=!0,t.classList.add("busy");try{be=await I().sync(),X(be.message,!be.ok)}catch(e){X(Se(e),!0)}finally{t.disabled=!1,t.classList.remove("busy"),P&&(Ke(),U?.())}}}async function En(){if(!P||document.visibilityState!=="visible"||ye.open)return;let t=P.version(),e=ge;try{await P.refresh(),ge="ok"}catch(n){ge=n instanceof ee?"signed-out":n instanceof Z?"stopped":ge}(P.version()!==t||e!==ge)&&(Ke(),U?.())}function ai(){window.addEventListener("hashchange",Kt),y("#c-form").addEventListener("submit",t=>{ri(t)}),ye.addEventListener("cancel",t=>{$n()&&!confirm(x.confirmDiscard)&&t.preventDefault()}),y("#c-file").addEventListener("change",t=>{let e=t.target;Bt(e.files??[]),e.value=""}),y("#c-text").addEventListener("paste",t=>{let e=[...t.clipboardData?.files??[]];e.length&&(t.preventDefault(),Bt(e))}),ye.addEventListener("dragover",t=>t.preventDefault()),ye.addEventListener("drop",t=>{t.preventDefault(),Bt(t.dataTransfer?.files??[])}),document.addEventListener("click",async t=>{let e=t.target,n=e.closest("[data-action],[data-filter-key],[data-date-after],[data-type-pick],[data-project-toggle],[data-remove-existing],[data-remove-new],.entry");if(!n)return;let s=n.dataset;if(s.filterKey!==void 0){ae&&(t.preventDefault(),ae.toggle(s.filterKey,s.filterValue??""));return}if(s.dateAfter!==void 0)return ae?.dates(s.dateAfter);if(s.typePick){Un(),g.type=s.typePick,ii(he(G,s.typePick)),Fn(),Kn();return}if(s.projectToggle){g.projects.has(s.projectToggle)?g.projects.delete(s.projectToggle):g.projects.add(s.projectToggle),mt();return}if(s.removeExisting){g.removed.has(s.removeExisting)?g.removed.delete(s.removeExisting):g.removed.add(s.removeExisting),ht();return}if(s.removeNew!==void 0){g.files.splice(Number(s.removeNew),1),ht();return}if(n.classList.contains("entry")){e.closest("a,button")||(location.hash=`#/entry/${encodeURIComponent(s.id)}`);return}switch(s.action){case"new":P&&_t({project:Tn()});break;case"close":(!$n()||confirm(x.confirmDiscard))&&Rn();break;case"new-project":case"composer-new-project":{let i=prompt(x.newProject)?.trim();if(!i)return;try{let r=await I().createProject(i);s.action==="composer-new-project"?(g.projects.add(r.slug),mt()):U?.()}catch(r){X(Se(r),!0)}break}case"clear-filters":ae?.clear();break;case"ask":Qs();break;case"close-answer":y("#answer").innerHTML="";break;case"edit":R&&_t({entry:R});break;case"history":R&&ti(R);break;case"delete":if(R&&confirm(x.confirmDelete))try{await I().deleteEntry(R.id,R),X(x.deleted),Ke(),location.hash="#/"}catch(i){X(Se(i),!0)}break;case"back":history.length>1?history.back():location.hash="#/";break;case"sync":oi();break}}),document.addEventListener("keydown",t=>{let e=t.target;if(ye.open){t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),y("#c-form").requestSubmit());return}!P||t.metaKey||t.ctrlKey||t.altKey||/^(INPUT|TEXTAREA|SELECT)$/.test(e.tagName)||(t.key==="n"?(t.preventDefault(),_t({project:Tn()})):t.key==="/"?(t.preventDefault(),ae||(location.hash="#/"),setTimeout(()=>y("#q")?.focus(),0)):t.key==="Enter"&&e.classList.contains("entry")&&(location.hash=`#/entry/${encodeURIComponent(e.dataset.id)}`))}),setInterval(()=>{En()},Fs),document.addEventListener("visibilitychange",()=>{En()})}var Ut=await Ue.connect();"error"in Ut?xn(Ut.error):Mn(Ut.store);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" rx="14" fill="#1d1a16"/><rect x="20" y="14" width="16" height="36" rx="3" fill="#b5501c"/><rect x="38" y="14" width="6" height="36" rx="2" fill="#f6f3ec"/></svg>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
+
<meta name="referrer" content="no-referrer">
|
|
7
|
+
<title>GitRoll</title>
|
|
8
|
+
<link rel="icon" href="icon.svg" type="image/svg+xml">
|
|
9
|
+
<link rel="stylesheet" href="style.css">
|
|
10
|
+
<link rel="stylesheet" href="theme.css">
|
|
11
|
+
<script type="module" src="app.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<header class="bar">
|
|
15
|
+
<a href="#/" class="brand"><span class="mark" aria-hidden="true"></span><span id="roll-name">GitRoll</span></a>
|
|
16
|
+
<nav aria-label="Main">
|
|
17
|
+
<a href="#/" data-nav="timeline">Timeline</a>
|
|
18
|
+
<a href="#/projects" data-nav="projects">Projects</a>
|
|
19
|
+
</nav>
|
|
20
|
+
<div class="bar-actions">
|
|
21
|
+
<button id="sync" class="secondary sync" data-action="sync">Sync<b id="sync-count" hidden></b></button>
|
|
22
|
+
<button class="primary" data-action="new">Log</button>
|
|
23
|
+
</div>
|
|
24
|
+
</header>
|
|
25
|
+
|
|
26
|
+
<main id="view"><p class="muted">Loading…</p></main>
|
|
27
|
+
|
|
28
|
+
<dialog id="composer" aria-labelledby="c-title">
|
|
29
|
+
<form id="c-form" method="dialog">
|
|
30
|
+
<header>
|
|
31
|
+
<h2 id="c-title">What happened?</h2>
|
|
32
|
+
<button type="button" class="icon" data-action="close" aria-label="Close">×</button>
|
|
33
|
+
</header>
|
|
34
|
+
|
|
35
|
+
<textarea id="c-text" rows="5" placeholder="Write what happened…" aria-label="What happened?"></textarea>
|
|
36
|
+
|
|
37
|
+
<label class="attach">Add photos or files<input id="c-file" type="file" multiple hidden></label>
|
|
38
|
+
<div id="c-files" class="files"></div>
|
|
39
|
+
|
|
40
|
+
<details id="c-more">
|
|
41
|
+
<summary>More options</summary>
|
|
42
|
+
<div class="group">
|
|
43
|
+
<span class="group-label">Kind</span>
|
|
44
|
+
<div id="c-types" class="chips"></div>
|
|
45
|
+
</div>
|
|
46
|
+
<div id="c-fields" class="grid"></div>
|
|
47
|
+
<div class="group">
|
|
48
|
+
<span class="group-label">Project</span>
|
|
49
|
+
<div id="c-projects" class="chips"></div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="grid">
|
|
52
|
+
<label>Amount<input id="c-amount" inputmode="decimal" placeholder="$0.00" autocomplete="off"></label>
|
|
53
|
+
<label>Date<input id="c-when" type="datetime-local"></label>
|
|
54
|
+
<label class="wide">Tags<input id="c-tags" placeholder="Separate with commas" autocomplete="off"></label>
|
|
55
|
+
</div>
|
|
56
|
+
</details>
|
|
57
|
+
|
|
58
|
+
<footer>
|
|
59
|
+
<button type="button" class="secondary" data-action="close">Cancel</button>
|
|
60
|
+
<button type="submit" id="c-submit" class="primary">Save</button>
|
|
61
|
+
</footer>
|
|
62
|
+
</form>
|
|
63
|
+
</dialog>
|
|
64
|
+
|
|
65
|
+
<div id="toast" role="status" aria-live="polite"></div>
|
|
66
|
+
</body>
|
|
67
|
+
</html>
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/*
|
|
2
|
+
GitRoll styles. Themes override the variables below from .gitroll/theme.css.
|
|
3
|
+
*/
|
|
4
|
+
:root {
|
|
5
|
+
--bg: #fafafa;
|
|
6
|
+
--surface: #ffffff;
|
|
7
|
+
--text: #18181b;
|
|
8
|
+
--muted: #71717a;
|
|
9
|
+
--faint: #a1a1aa;
|
|
10
|
+
--line: #e4e4e7;
|
|
11
|
+
--hover: #f4f4f5;
|
|
12
|
+
--accent: #18181b;
|
|
13
|
+
--accent-text: #ffffff;
|
|
14
|
+
--link: #2563eb;
|
|
15
|
+
--danger: #b91c1c;
|
|
16
|
+
--danger-bg: #fef2f2;
|
|
17
|
+
--notice-bg: #f4f4f5;
|
|
18
|
+
--add-bg: #ecfdf5;
|
|
19
|
+
--add: #047857;
|
|
20
|
+
--del-bg: #fef2f2;
|
|
21
|
+
--del: #b91c1c;
|
|
22
|
+
--radius: 10px;
|
|
23
|
+
--font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
24
|
+
--mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
25
|
+
color-scheme: light;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@media (prefers-color-scheme: dark) {
|
|
29
|
+
:root {
|
|
30
|
+
--bg: #09090b;
|
|
31
|
+
--surface: #18181b;
|
|
32
|
+
--text: #fafafa;
|
|
33
|
+
--muted: #a1a1aa;
|
|
34
|
+
--faint: #71717a;
|
|
35
|
+
--line: #27272a;
|
|
36
|
+
--hover: #27272a;
|
|
37
|
+
--accent: #fafafa;
|
|
38
|
+
--accent-text: #18181b;
|
|
39
|
+
--link: #60a5fa;
|
|
40
|
+
--danger: #f87171;
|
|
41
|
+
--danger-bg: #2a1215;
|
|
42
|
+
--notice-bg: #1f1f23;
|
|
43
|
+
--add-bg: #052e22;
|
|
44
|
+
--add: #6ee7b7;
|
|
45
|
+
--del-bg: #2a1215;
|
|
46
|
+
--del: #fca5a5;
|
|
47
|
+
color-scheme: dark;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
* { box-sizing: border-box; }
|
|
52
|
+
html { -webkit-text-size-adjust: 100%; }
|
|
53
|
+
body { margin: 0; background: var(--bg); color: var(--text); font: 15px/1.55 var(--font); }
|
|
54
|
+
a { color: inherit; }
|
|
55
|
+
button, input, select, textarea { font: inherit; color: inherit; }
|
|
56
|
+
:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
|
|
57
|
+
[hidden] { display: none !important; }
|
|
58
|
+
code, .cmd { font-family: var(--mono); font-size: 0.9em; }
|
|
59
|
+
.muted { color: var(--muted); }
|
|
60
|
+
.small { font-size: 0.85rem; }
|
|
61
|
+
|
|
62
|
+
/* Buttons */
|
|
63
|
+
button { cursor: pointer; border-radius: 8px; padding: 0.45rem 0.9rem; border: 1px solid transparent; background: none; line-height: 1.2; }
|
|
64
|
+
button:disabled { opacity: 0.5; cursor: default; }
|
|
65
|
+
button.primary { background: var(--accent); color: var(--accent-text); font-weight: 600; }
|
|
66
|
+
button.primary:hover:not(:disabled) { opacity: 0.88; }
|
|
67
|
+
button.secondary { background: var(--surface); border-color: var(--line); }
|
|
68
|
+
button.secondary:hover:not(:disabled) { background: var(--hover); }
|
|
69
|
+
button.danger { color: var(--danger); }
|
|
70
|
+
button.link { padding: 0; color: var(--link); }
|
|
71
|
+
button.link:hover { text-decoration: underline; }
|
|
72
|
+
button.icon { color: var(--muted); font-size: 1.4rem; padding: 0.1rem 0.5rem; }
|
|
73
|
+
button.icon:hover { color: var(--text); }
|
|
74
|
+
|
|
75
|
+
input, select, textarea { width: 100%; border: 1px solid var(--line); background: var(--surface); border-radius: 8px; padding: 0.55rem 0.7rem; }
|
|
76
|
+
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--muted); }
|
|
77
|
+
label { display: grid; gap: 0.3rem; font-size: 0.85rem; color: var(--muted); }
|
|
78
|
+
label.check { display: flex; align-items: center; gap: 0.5rem; color: var(--text); }
|
|
79
|
+
label.check input { width: auto; }
|
|
80
|
+
|
|
81
|
+
/* Header */
|
|
82
|
+
.bar { position: sticky; top: 0; z-index: 10; display: none; align-items: center; gap: 1rem; padding: 0.65rem 1.25rem; background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
|
|
83
|
+
body.connected .bar { display: flex; }
|
|
84
|
+
.brand { display: flex; align-items: center; gap: 0.55rem; font-weight: 650; text-decoration: none; min-width: 0; }
|
|
85
|
+
.brand #roll-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 16rem; }
|
|
86
|
+
.mark { flex: none; width: 0.7rem; height: 0.95rem; border-radius: 2px; background: var(--accent); }
|
|
87
|
+
.bar nav { display: flex; gap: 0.15rem; }
|
|
88
|
+
.bar nav a { text-decoration: none; color: var(--muted); padding: 0.35rem 0.65rem; border-radius: 8px; }
|
|
89
|
+
.bar nav a:hover { color: var(--text); }
|
|
90
|
+
.bar nav a[aria-current="page"] { color: var(--text); background: var(--hover); }
|
|
91
|
+
.bar-actions { margin-left: auto; display: flex; gap: 0.5rem; align-items: center; }
|
|
92
|
+
.sync { display: inline-flex; align-items: center; gap: 0.4rem; }
|
|
93
|
+
.sync b { background: var(--accent); color: var(--accent-text); border-radius: 999px; padding: 0 0.45em; font-size: 0.72rem; }
|
|
94
|
+
.sync.busy { opacity: 0.6; }
|
|
95
|
+
|
|
96
|
+
main { max-width: 44rem; margin: 0 auto; padding: 1.5rem 1.25rem 5rem; }
|
|
97
|
+
|
|
98
|
+
/* Notices */
|
|
99
|
+
.notice { max-width: 30rem; margin: 15vh auto 0; text-align: center; }
|
|
100
|
+
.notice h1 { font-size: 1.6rem; margin: 0 0 0.75rem; }
|
|
101
|
+
.cmd { display: inline-block; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 0.6rem 1rem; }
|
|
102
|
+
.banner { background: var(--notice-bg); border-radius: var(--radius); padding: 0.65rem 0.9rem; margin: 0 0 1rem; font-size: 0.9rem; }
|
|
103
|
+
.banner.error { background: var(--danger-bg); color: var(--danger); }
|
|
104
|
+
.banner summary { cursor: pointer; }
|
|
105
|
+
|
|
106
|
+
/* Search */
|
|
107
|
+
.find { margin-bottom: 0.5rem; }
|
|
108
|
+
.searchbox { display: flex; gap: 0.5rem; }
|
|
109
|
+
.searchbox input { font-size: 1rem; padding: 0.7rem 0.9rem; border-radius: var(--radius); }
|
|
110
|
+
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.65rem; }
|
|
111
|
+
.chips:empty { display: none; }
|
|
112
|
+
.chip { font-size: 0.85rem; padding: 0.3rem 0.75rem; border: 1px solid var(--line); border-radius: 999px; background: var(--surface); color: var(--muted); }
|
|
113
|
+
.chip:hover { color: var(--text); }
|
|
114
|
+
.chip.on { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
|
|
115
|
+
.chip span { opacity: 0.7; margin-left: 0.2rem; }
|
|
116
|
+
.chip.add { border-style: dashed; }
|
|
117
|
+
.summary { color: var(--muted); font-size: 0.88rem; margin: 0.75rem 0 0; }
|
|
118
|
+
.answer { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 1.1rem; margin: 1rem 0; }
|
|
119
|
+
.answer p { margin: 0 0 0.6rem; }
|
|
120
|
+
.cite { color: var(--link); font-size: 0.8rem; margin-left: 0.2rem; }
|
|
121
|
+
|
|
122
|
+
/* Timeline */
|
|
123
|
+
.day h2 { font-size: 0.8rem; font-weight: 600; color: var(--muted); margin: 1.75rem 0 0.25rem; }
|
|
124
|
+
.entry { display: grid; grid-template-columns: 4.75rem 1fr; gap: 1rem; padding: 0.9rem 0.5rem; margin: 0 -0.5rem; border-radius: var(--radius); cursor: pointer; }
|
|
125
|
+
.entry:hover { background: var(--hover); }
|
|
126
|
+
.when { font-size: 0.85rem; color: var(--muted); padding-top: 0.1rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
127
|
+
.content { min-width: 0; }
|
|
128
|
+
.labels { display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem; align-items: baseline; font-size: 0.85rem; margin-bottom: 0.15rem; }
|
|
129
|
+
.labels a { text-decoration: none; }
|
|
130
|
+
.labels a:hover, .foot a:hover { text-decoration: underline; }
|
|
131
|
+
.labels .project { font-weight: 600; }
|
|
132
|
+
.labels .kind { color: var(--muted); }
|
|
133
|
+
.amount { font-variant-numeric: tabular-nums; font-weight: 600; }
|
|
134
|
+
.body { overflow-wrap: anywhere; }
|
|
135
|
+
.body p { margin: 0 0 0.4rem; }
|
|
136
|
+
.body p:last-child { margin-bottom: 0; }
|
|
137
|
+
.body a { color: var(--link); }
|
|
138
|
+
.body .tag { text-decoration: none; }
|
|
139
|
+
.body.large { font-size: 1.1rem; margin: 0.75rem 0; }
|
|
140
|
+
.fields { display: flex; flex-wrap: wrap; gap: 0.15rem 1rem; font-size: 0.85rem; margin-top: 0.3rem; }
|
|
141
|
+
.fields small { color: var(--muted); }
|
|
142
|
+
.thumbs { display: flex; gap: 0.4rem; margin-top: 0.55rem; align-items: center; }
|
|
143
|
+
.thumbs img { width: 4.25rem; height: 4.25rem; object-fit: cover; border-radius: 8px; background: var(--line); }
|
|
144
|
+
.thumbs .more { color: var(--muted); font-size: 0.85rem; }
|
|
145
|
+
.foot { display: flex; flex-wrap: wrap; gap: 0.15rem 0.75rem; margin-top: 0.4rem; font-size: 0.82rem; color: var(--muted); }
|
|
146
|
+
.foot a { text-decoration: none; }
|
|
147
|
+
.empty { text-align: center; padding: 3.5rem 1rem; }
|
|
148
|
+
.empty .big { font-size: 1.35rem; font-weight: 600; margin: 0 0 0.25rem; }
|
|
149
|
+
.broken { opacity: 0.3; }
|
|
150
|
+
|
|
151
|
+
/* Lists */
|
|
152
|
+
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1rem; }
|
|
153
|
+
.page-head h1 { margin: 0; font-size: 1.4rem; }
|
|
154
|
+
.list { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.5rem; }
|
|
155
|
+
.row { display: grid; gap: 0.1rem; text-decoration: none; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 0.8rem 1rem; }
|
|
156
|
+
.row:hover { background: var(--hover); }
|
|
157
|
+
.row span { color: var(--muted); font-size: 0.85rem; }
|
|
158
|
+
|
|
159
|
+
/* Event */
|
|
160
|
+
.back { margin-bottom: 1rem; display: inline-block; }
|
|
161
|
+
.detail { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 1.25rem 1.4rem; }
|
|
162
|
+
.detail > time { display: block; color: var(--muted); font-size: 0.9rem; margin-bottom: 0.4rem; }
|
|
163
|
+
.facts { display: grid; grid-template-columns: max-content 1fr; gap: 0.35rem 1rem; margin: 1rem 0 0; font-size: 0.92rem; }
|
|
164
|
+
.facts dt { color: var(--muted); }
|
|
165
|
+
.facts dd { margin: 0; overflow-wrap: anywhere; }
|
|
166
|
+
.attachments { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: 0.6rem; margin-top: 1rem; }
|
|
167
|
+
.att { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; text-decoration: none; background: var(--bg); }
|
|
168
|
+
.att.img img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; }
|
|
169
|
+
.att.file { display: grid; gap: 0.15rem; padding: 0.75rem; }
|
|
170
|
+
.kind { font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--muted); }
|
|
171
|
+
.fname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.88rem; }
|
|
172
|
+
.att small { color: var(--muted); }
|
|
173
|
+
.actions { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 1.25rem; }
|
|
174
|
+
.more-info { margin-top: 1.25rem; font-size: 0.88rem; }
|
|
175
|
+
.more-info summary { cursor: pointer; color: var(--muted); }
|
|
176
|
+
.history h2 { font-size: 1rem; margin: 1.5rem 0 0.5rem; }
|
|
177
|
+
.revs { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.9rem; }
|
|
178
|
+
.rev-head { font-size: 0.88rem; color: var(--muted); }
|
|
179
|
+
.rev-head strong { color: var(--text); }
|
|
180
|
+
.diff { font-family: var(--font); font-size: 0.88rem; background: var(--bg); border-radius: 8px; padding: 0.5rem; margin: 0.35rem 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
181
|
+
.diff span { display: block; padding: 0.1rem 0.4rem; border-radius: 4px; }
|
|
182
|
+
.diff .add { background: var(--add-bg); color: var(--add); }
|
|
183
|
+
.diff .del { background: var(--del-bg); color: var(--del); text-decoration: line-through; }
|
|
184
|
+
|
|
185
|
+
/* Composer */
|
|
186
|
+
dialog#composer { width: min(36rem, calc(100vw - 2rem)); max-height: calc(100vh - 2rem); border: 1px solid var(--line); border-radius: 16px; padding: 0; background: var(--surface); color: var(--text); box-shadow: 0 20px 60px rgb(0 0 0 / 20%); }
|
|
187
|
+
dialog::backdrop { background: rgb(0 0 0 / 35%); }
|
|
188
|
+
#c-form { display: grid; gap: 0.85rem; padding: 1.1rem 1.25rem 1.25rem; }
|
|
189
|
+
#c-form header { display: flex; justify-content: space-between; align-items: center; }
|
|
190
|
+
#c-form h2 { margin: 0; font-size: 1.15rem; }
|
|
191
|
+
#c-text { font-size: 1.05rem; min-height: 8rem; resize: vertical; padding: 0.75rem; }
|
|
192
|
+
.attach { display: flex; justify-content: center; cursor: pointer; border: 1px dashed var(--line); border-radius: var(--radius); padding: 0.7rem; color: var(--muted); font-size: 0.92rem; }
|
|
193
|
+
.attach:hover { color: var(--text); background: var(--hover); }
|
|
194
|
+
.files { display: grid; gap: 0.35rem; }
|
|
195
|
+
.files:empty { display: none; }
|
|
196
|
+
.file { display: flex; align-items: center; gap: 0.6rem; background: var(--bg); border-radius: 8px; padding: 0.35rem 0.6rem 0.35rem 0.35rem; }
|
|
197
|
+
.file img { width: 2.5rem; height: 2.5rem; object-fit: cover; border-radius: 6px; }
|
|
198
|
+
.file .kind { width: 2.5rem; text-align: center; }
|
|
199
|
+
.file .fname { flex: 1; min-width: 0; }
|
|
200
|
+
.file small { color: var(--muted); font-size: 0.8rem; }
|
|
201
|
+
.file.removed { opacity: 0.45; }
|
|
202
|
+
#c-more summary { cursor: pointer; color: var(--muted); font-size: 0.92rem; }
|
|
203
|
+
#c-more[open] { display: grid; gap: 0.85rem; }
|
|
204
|
+
#c-more > summary { margin-bottom: 0.1rem; }
|
|
205
|
+
.group-label { font-size: 0.85rem; color: var(--muted); }
|
|
206
|
+
.group .chips { margin-top: 0.35rem; }
|
|
207
|
+
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: 0.7rem; }
|
|
208
|
+
.grid:empty { display: none; }
|
|
209
|
+
.grid .wide { grid-column: 1 / -1; }
|
|
210
|
+
#c-form footer { display: flex; justify-content: flex-end; gap: 0.5rem; padding-top: 0.25rem; }
|
|
211
|
+
|
|
212
|
+
#toast { position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, 0.75rem); max-width: min(32rem, calc(100vw - 2rem)); background: var(--accent); color: var(--accent-text); padding: 0.6rem 1rem; border-radius: var(--radius); font-size: 0.9rem; opacity: 0; pointer-events: none; transition: 0.2s; z-index: 50; text-align: center; }
|
|
213
|
+
#toast.show { opacity: 1; transform: translate(-50%, 0); }
|
|
214
|
+
#toast.error { background: var(--danger); color: #fff; }
|
|
215
|
+
|
|
216
|
+
@media (max-width: 640px) {
|
|
217
|
+
.bar { gap: 0.5rem; padding: 0.6rem 0.9rem; }
|
|
218
|
+
.brand #roll-name { max-width: 7rem; }
|
|
219
|
+
.bar nav a { padding: 0.3rem 0.45rem; }
|
|
220
|
+
main { padding: 1rem 0.9rem 4rem; }
|
|
221
|
+
.entry { grid-template-columns: 1fr; gap: 0.1rem; }
|
|
222
|
+
dialog#composer { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh; margin: 0; border-radius: 0; }
|
|
223
|
+
.detail { padding: 1rem; }
|
|
224
|
+
}
|