texlite 0.7.0 → 0.7.2
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/dist/client/assets/{BinaryModule-Aj1vLnwf-wCY0vy1F.js → BinaryModule-Aj1vLnwf-wAe5fMVe.js} +1 -1
- package/dist/client/assets/GitDialog-b7cWzpdJ.js +3 -0
- package/dist/client/assets/{HistoryDialog-qZKt59En.js → HistoryDialog-F8tDuD3v.js} +1 -1
- package/dist/client/assets/LatexEditor-BT2E5IIK.js +59 -0
- package/dist/client/assets/PdfPreview-C2tw6xhu.js +1 -0
- package/dist/client/assets/{ProjectNavigationDialogs-CcHy9xt5.js → ProjectNavigationDialogs-CzrF5eh5.js} +1 -1
- package/dist/client/assets/{SystemMetricsDialog-BSiZRWs4.js → SystemMetricsDialog-OAoXCVVy.js} +1 -1
- package/dist/client/assets/binary-CWru8eff.js +1 -0
- package/dist/client/assets/index-BLOqf18q.js +62 -0
- package/dist/client/assets/index-CwGialPz.css +1 -0
- package/dist/client/assets/{index-BM28jYXo.js → index-JmuE6_j5.js} +1 -1
- package/dist/client/assets/minus-D0DZYQR6.js +1 -0
- package/dist/client/assets/{spellCheck-Cs5UpEXV.js → spellCheck-TTrb0uqA.js} +3 -3
- package/dist/client/index.html +2 -2
- package/dist/server/app.js +315 -2
- package/dist/server/citationLibrary.js +174 -0
- package/dist/server/db.js +37 -0
- package/package.json +2 -1
- package/dist/client/assets/GitDialog-BNzmjKSK.js +0 -3
- package/dist/client/assets/LatexEditor-CpK2QB28.js +0 -59
- package/dist/client/assets/PdfPreview-Deo1bzQ7.js +0 -1
- package/dist/client/assets/binary-DEDGh9yV.js +0 -1
- package/dist/client/assets/index-DJzyhcDQ.js +0 -17
- package/dist/client/assets/index-DdrajKQB.css +0 -1
- package/dist/client/assets/plus-BmrCa7ds.js +0 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small, dependency-free BibTeX entry parser used by the personal citation
|
|
3
|
+
* library. It deliberately preserves the original entry text so importing a
|
|
4
|
+
* reference never rewrites formatting chosen by the library owner.
|
|
5
|
+
*/
|
|
6
|
+
const ignoredEntryTypes = new Set(["comment", "string", "preamble"]);
|
|
7
|
+
export const MAX_CITATION_BIBTEX_BYTES = 512 * 1024;
|
|
8
|
+
export function parseBibEntries(source) {
|
|
9
|
+
const entries = [];
|
|
10
|
+
let searchFrom = 0;
|
|
11
|
+
while (searchFrom < source.length) {
|
|
12
|
+
const at = source.indexOf("@", searchFrom);
|
|
13
|
+
if (at < 0)
|
|
14
|
+
break;
|
|
15
|
+
searchFrom = at + 1;
|
|
16
|
+
const lineStart = source.lastIndexOf("\n", at - 1) + 1;
|
|
17
|
+
if (isCommented(source, lineStart, at))
|
|
18
|
+
continue;
|
|
19
|
+
const header = source.slice(at).match(/^@([A-Za-z][A-Za-z0-9_-]*)\s*([\{\(])/);
|
|
20
|
+
if (!header || header.index === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
const opening = at + header[0].length - 1;
|
|
23
|
+
const closing = matchingDelimiter(source, opening, header[2] === "{" ? "}" : ")");
|
|
24
|
+
if (closing < 0)
|
|
25
|
+
continue;
|
|
26
|
+
const raw = source.slice(at, closing + 1).trim();
|
|
27
|
+
const parsed = parseSingleBibEntry(raw);
|
|
28
|
+
if (parsed && !ignoredEntryTypes.has(parsed.entryType.toLowerCase()))
|
|
29
|
+
entries.push(parsed);
|
|
30
|
+
searchFrom = closing + 1;
|
|
31
|
+
}
|
|
32
|
+
return entries;
|
|
33
|
+
}
|
|
34
|
+
function isCommented(source, lineStart, end) {
|
|
35
|
+
let escaped = false;
|
|
36
|
+
for (let index = lineStart; index < end; index += 1) {
|
|
37
|
+
const character = source[index];
|
|
38
|
+
if (character === "%" && !escaped)
|
|
39
|
+
return true;
|
|
40
|
+
if (character === "\\")
|
|
41
|
+
escaped = !escaped;
|
|
42
|
+
else
|
|
43
|
+
escaped = false;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
export function parseSingleBibEntry(source) {
|
|
48
|
+
const bibtex = source.trim();
|
|
49
|
+
if (!bibtex || new TextEncoder().encode(bibtex).length > MAX_CITATION_BIBTEX_BYTES)
|
|
50
|
+
return null;
|
|
51
|
+
const header = bibtex.match(/^@([A-Za-z][A-Za-z0-9_-]*)\s*([\{\(])\s*([^,\s\}\)]+)\s*,/s);
|
|
52
|
+
if (!header)
|
|
53
|
+
return null;
|
|
54
|
+
const opening = bibtex.indexOf(header[2], header.index ?? 0);
|
|
55
|
+
const closing = matchingDelimiter(bibtex, opening, header[2] === "{" ? "}" : ")");
|
|
56
|
+
if (closing !== bibtex.length - 1)
|
|
57
|
+
return null;
|
|
58
|
+
const entryType = header[1];
|
|
59
|
+
if (ignoredEntryTypes.has(entryType.toLowerCase()))
|
|
60
|
+
return null;
|
|
61
|
+
const fields = parseFields(bibtex.slice(header[0].length, -1));
|
|
62
|
+
if (!fields)
|
|
63
|
+
return null;
|
|
64
|
+
return {
|
|
65
|
+
citationKey: header[3],
|
|
66
|
+
entryType,
|
|
67
|
+
bibtex,
|
|
68
|
+
title: fields.title ?? null,
|
|
69
|
+
authors: fields.author ?? null,
|
|
70
|
+
year: fields.year ?? null
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function matchingDelimiter(source, opening, closingCharacter) {
|
|
74
|
+
let outerDepth = 0;
|
|
75
|
+
let braceDepth = 0;
|
|
76
|
+
let quoted = false;
|
|
77
|
+
let escaped = false;
|
|
78
|
+
for (let index = opening; index < source.length; index += 1) {
|
|
79
|
+
const character = source[index];
|
|
80
|
+
if (escaped) {
|
|
81
|
+
escaped = false;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (character === "\\") {
|
|
85
|
+
escaped = true;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (closingCharacter === "}") {
|
|
89
|
+
if (character === '"' && outerDepth === 1)
|
|
90
|
+
quoted = !quoted;
|
|
91
|
+
if (character === "{")
|
|
92
|
+
outerDepth += 1;
|
|
93
|
+
else if (character === "}" && --outerDepth === 0)
|
|
94
|
+
return index;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (character === "{" && !quoted) {
|
|
98
|
+
braceDepth += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (character === "}" && !quoted && braceDepth > 0) {
|
|
102
|
+
braceDepth -= 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (braceDepth > 0)
|
|
106
|
+
continue;
|
|
107
|
+
if (character === '"') {
|
|
108
|
+
quoted = !quoted;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (quoted)
|
|
112
|
+
continue;
|
|
113
|
+
if (character === "(")
|
|
114
|
+
outerDepth += 1;
|
|
115
|
+
else if (character === ")" && --outerDepth === 0)
|
|
116
|
+
return index;
|
|
117
|
+
}
|
|
118
|
+
return -1;
|
|
119
|
+
}
|
|
120
|
+
function parseFields(body) {
|
|
121
|
+
const fields = {};
|
|
122
|
+
for (const segment of splitTopLevel(body, ",")) {
|
|
123
|
+
if (!segment.trim())
|
|
124
|
+
continue;
|
|
125
|
+
const match = segment.match(/^\s*([A-Za-z][A-Za-z0-9_-]*)\s*=\s*([\s\S]*)$/);
|
|
126
|
+
if (!match || !match[2].trim())
|
|
127
|
+
return null;
|
|
128
|
+
const value = cleanFieldValue(match[2]);
|
|
129
|
+
if (value)
|
|
130
|
+
fields[match[1].toLowerCase()] = value;
|
|
131
|
+
}
|
|
132
|
+
return fields;
|
|
133
|
+
}
|
|
134
|
+
function splitTopLevel(source, separator) {
|
|
135
|
+
const result = [];
|
|
136
|
+
let start = 0;
|
|
137
|
+
let depth = 0;
|
|
138
|
+
let quoted = false;
|
|
139
|
+
let escaped = false;
|
|
140
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
141
|
+
const character = source[index];
|
|
142
|
+
if (escaped) {
|
|
143
|
+
escaped = false;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (character === "\\") {
|
|
147
|
+
escaped = true;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (character === '"') {
|
|
151
|
+
quoted = !quoted;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (quoted)
|
|
155
|
+
continue;
|
|
156
|
+
if (character === "{")
|
|
157
|
+
depth += 1;
|
|
158
|
+
else if (character === "}")
|
|
159
|
+
depth = Math.max(0, depth - 1);
|
|
160
|
+
else if (character === separator && depth === 0) {
|
|
161
|
+
result.push(source.slice(start, index));
|
|
162
|
+
start = index + 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
result.push(source.slice(start));
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
function cleanFieldValue(value) {
|
|
169
|
+
let result = value.trim();
|
|
170
|
+
if ((result.startsWith("{") && result.endsWith("}")) || (result.startsWith('"') && result.endsWith('"'))) {
|
|
171
|
+
result = result.slice(1, -1);
|
|
172
|
+
}
|
|
173
|
+
return result.replace(/\s+/g, " ").trim();
|
|
174
|
+
}
|
package/dist/server/db.js
CHANGED
|
@@ -179,6 +179,39 @@ function migrate(db) {
|
|
|
179
179
|
);
|
|
180
180
|
CREATE INDEX IF NOT EXISTS project_dictionary_words_project_id ON project_dictionary_words(project_id);
|
|
181
181
|
|
|
182
|
+
CREATE TABLE IF NOT EXISTS citation_library_entries (
|
|
183
|
+
id TEXT PRIMARY KEY,
|
|
184
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
185
|
+
citation_key TEXT NOT NULL COLLATE NOCASE,
|
|
186
|
+
entry_type TEXT NOT NULL,
|
|
187
|
+
bibtex TEXT NOT NULL,
|
|
188
|
+
title TEXT,
|
|
189
|
+
authors TEXT,
|
|
190
|
+
year TEXT,
|
|
191
|
+
revision INTEGER NOT NULL DEFAULT 1,
|
|
192
|
+
created_at TEXT NOT NULL,
|
|
193
|
+
updated_at TEXT NOT NULL,
|
|
194
|
+
UNIQUE (user_id, citation_key)
|
|
195
|
+
);
|
|
196
|
+
CREATE INDEX IF NOT EXISTS citation_library_entries_user_updated
|
|
197
|
+
ON citation_library_entries(user_id, updated_at DESC);
|
|
198
|
+
|
|
199
|
+
CREATE TABLE IF NOT EXISTS citation_library_tags (
|
|
200
|
+
id TEXT PRIMARY KEY,
|
|
201
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
202
|
+
name TEXT NOT NULL COLLATE NOCASE,
|
|
203
|
+
color TEXT NOT NULL CHECK (color IN ('red', 'orange', 'yellow', 'green', 'blue', 'purple', 'gray')),
|
|
204
|
+
created_at TEXT NOT NULL,
|
|
205
|
+
UNIQUE (user_id, name)
|
|
206
|
+
);
|
|
207
|
+
CREATE TABLE IF NOT EXISTS citation_library_entry_tags (
|
|
208
|
+
entry_id TEXT NOT NULL REFERENCES citation_library_entries(id) ON DELETE CASCADE,
|
|
209
|
+
tag_id TEXT NOT NULL REFERENCES citation_library_tags(id) ON DELETE CASCADE,
|
|
210
|
+
created_at TEXT NOT NULL,
|
|
211
|
+
PRIMARY KEY (entry_id, tag_id)
|
|
212
|
+
);
|
|
213
|
+
CREATE INDEX IF NOT EXISTS citation_library_entry_tags_tag_id ON citation_library_entry_tags(tag_id);
|
|
214
|
+
|
|
182
215
|
CREATE TABLE IF NOT EXISTS project_git_settings (
|
|
183
216
|
project_id TEXT PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
|
|
184
217
|
token_ciphertext TEXT,
|
|
@@ -224,6 +257,10 @@ function migrate(db) {
|
|
|
224
257
|
if (!compileRunColumns.some((column) => column.name === "main_file")) {
|
|
225
258
|
db.exec("ALTER TABLE compile_runs ADD COLUMN main_file TEXT NOT NULL DEFAULT ''");
|
|
226
259
|
}
|
|
260
|
+
const citationColumns = db.prepare("PRAGMA table_info(citation_library_entries)").all();
|
|
261
|
+
if (!citationColumns.some((column) => column.name === "revision")) {
|
|
262
|
+
db.exec("ALTER TABLE citation_library_entries ADD COLUMN revision INTEGER NOT NULL DEFAULT 1");
|
|
263
|
+
}
|
|
227
264
|
db.exec(`
|
|
228
265
|
UPDATE users SET can_create_projects = 1 WHERE role = 'admin';
|
|
229
266
|
UPDATE projects SET last_modified_by = owner_id WHERE last_modified_by IS NULL;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "texlite",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "A lightweight local-first collaborative LaTeX workspace",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"@radix-ui/react-dialog": "^1.1.15",
|
|
70
70
|
"@replit/codemirror-vim": "^6.4.0",
|
|
71
71
|
"better-sqlite3": "^13.0.2",
|
|
72
|
+
"bibtex-tidy": "1.14.0",
|
|
72
73
|
"diff-match-patch": "^1.0.5",
|
|
73
74
|
"fastify": "^5.4.0",
|
|
74
75
|
"harper.js": "^2.7.0",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{u as ye,r as n,j as e}from"./react-CsO_xvbl.js";import{i as h,M as H,L as p,G as q,C as ie,j as ne,T as ke,R as be,k as l}from"./index-DJzyhcDQ.js";import{M as ve,P as Ce,a as Ne}from"./plus-BmrCa7ds.js";const we=h("CloudUpload",[["path",{d:"M12 13v8",key:"1l5pq0"}],["path",{d:"M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242",key:"1pljnt"}],["path",{d:"m8 17 4-4 4 4",key:"1quai1"}]]);const ae=h("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]);const G=h("Eye",[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);const oe=h("GitCommitHorizontal",[["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}],["line",{x1:"3",x2:"9",y1:"12",y2:"12",key:"1dyftd"}],["line",{x1:"15",x2:"21",y1:"12",y2:"12",key:"oup4p8"}]]);const W=h("Github",[["path",{d:"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4",key:"tonef"}],["path",{d:"M9 18c-4.51 2-5-2-7-2",key:"9comsn"}]]);const ze=h("KeyRound",[["path",{d:"M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z",key:"1s6t7t"}],["circle",{cx:"16.5",cy:"7.5",r:".5",fill:"currentColor",key:"w0ekpg"}]]);const Se=h("Minimize2",[["polyline",{points:"4 14 10 14 10 20",key:"11kfnr"}],["polyline",{points:"20 10 14 10 14 4",key:"rlmsce"}],["line",{x1:"14",x2:"21",y1:"10",y2:"3",key:"o5lafz"}],["line",{x1:"3",x2:"10",y1:"21",y2:"14",key:"1atl0r"}]]);const Ee=h("RefreshCcw",[["path",{d:"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"14sxne"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16",key:"1hlbsb"}],["path",{d:"M16 16h5v5",key:"ccwih5"}]]);const Te=h("Undo2",[["path",{d:"M9 14 4 9l5-5",key:"102s5s"}],["path",{d:"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11",key:"f3b9sd"}]]);function Ue({open:g,project:o,onOpenChange:y,onBeforeMutation:r}){const{t:s,i18n:E}=ye(),[i,m]=n.useState(null),[J,V]=n.useState([]),[T,k]=n.useState(""),[F,K]=n.useState(()=>re(o.name)),[_,ce]=n.useState(!0),[D,Z]=n.useState(""),[b,M]=n.useState(null),[f,j]=n.useState(null),[R,U]=n.useState(!1),[le,v]=n.useState(!1),[$,L]=n.useState(!0),[P,A]=n.useState(!0),[a,C]=n.useState(""),[Q,N]=n.useState(""),[X,B]=n.useState(""),[u,x]=n.useState(!1),[w,Y]=n.useState(10),O=n.useRef(null),z=async(t=!1)=>{const c=await l(`/api/projects/${o.id}/git`);if(m(c.status),t&&(L(!c.status.tokenConfigured),A(!c.status.remoteUrl)),c.status.initialized&&c.status.latestCommit){const S=await l(`/api/projects/${o.id}/git/history`);V(S.commits)}else V([])};n.useEffect(()=>{if(!g){document.fullscreenElement&&document.exitFullscreen().catch(()=>{}),x(!1),k("");return}N(""),B(""),M(null),x(!1),K(re(o.name)),C("load"),r().then(()=>z(!0)).catch(t=>N(t instanceof Error?t.message:s("errors.generic"))).finally(()=>C(""))},[g,o.id]),n.useEffect(()=>{const t=()=>x(document.fullscreenElement===O.current);return document.addEventListener("fullscreenchange",t),()=>document.removeEventListener("fullscreenchange",t)},[]),n.useEffect(()=>{if(!u)return;const t=c=>{c.key==="Escape"&&!document.fullscreenElement&&x(!1)};return window.addEventListener("keydown",t),()=>window.removeEventListener("keydown",t)},[u]);const d=async(t,c,S,ee)=>{C(t),N(""),B("");try{await c(),S&&B(S)}catch(se){const te=se instanceof Error?se.message:s("errors.generic");N(ee?`${ee}: ${te}`:te)}finally{C("")}},de=()=>d("token",async()=>{const t=await l(`/api/projects/${o.id}/git/token`,{method:"PUT",body:JSON.stringify({token:T})});m(t.status),k(""),L(!1)},s("git.tokenSaved")),he=()=>d("remove-token",async()=>{const t=await l(`/api/projects/${o.id}/git/token`,{method:"DELETE"});m(t.status),k("")},s("git.tokenRemoved")),ge=()=>d("repository",async()=>{const t=await l(`/api/projects/${o.id}/git/repository`,{method:"POST",body:JSON.stringify({name:F,private:_})});m(t.status),A(!1)},s("git.repositoryCreated")),ue=()=>d("commit",async()=>{if(!await r())throw new Error(s("errors.collaborationUnavailable"));const t=await l(`/api/projects/${o.id}/git/commit`,{method:"POST",body:JSON.stringify({message:D})});m(t.status),Z(""),M(null),await z()},s("git.committed")),me=()=>d("push",async()=>{if(!await r())throw new Error(s("errors.collaborationUnavailable"));const t=await l(`/api/projects/${o.id}/git/push`,{method:"POST"});m(t.status),await z()},s("git.pushed"),s("git.pushFailed")),I=t=>d("diff",async()=>{if(!await r())throw new Error(s("errors.collaborationUnavailable"));const c=t?`?revision=${encodeURIComponent(t)}`:"";M(await l(`/api/projects/${o.id}/git/diff${c}`))}),fe=async()=>{if(u){document.fullscreenElement&&await document.exitFullscreen().catch(()=>{}),x(!1);return}const t=O.current;if(t?.requestFullscreen)try{await t.requestFullscreen()}catch{}x(!0)},xe=()=>{const t=f;t&&(j(null),d("checkout",async()=>{if(!await r())throw new Error(s("errors.collaborationUnavailable"));await l(`/api/projects/${o.id}/git/checkout`,{method:"POST",body:JSON.stringify({revision:t==="branch"?null:t.sha,force:R})}),window.location.reload()}))},pe=()=>{v(!1),d("discard",async()=>{if(!await r())throw new Error(s("errors.collaborationUnavailable"));await l(`/api/projects/${o.id}/git/discard`,{method:"POST"}),window.location.reload()})},je=a==="load"&&!i;return e.jsxs(e.Fragment,{children:[e.jsx(H,{open:g,extraWide:!0,className:u?"git-dialog-modal-fullscreen":void 0,title:s("git.title"),description:s("git.description"),onOpenChange:y,footer:e.jsx("button",{onClick:()=>y(!1),children:s("common.close")}),children:e.jsxs("div",{className:"git-dialog",children:[je&&e.jsxs("div",{className:"git-loading",children:[e.jsx(p,{className:"spin",size:22}),s("common.loading")]}),Q&&e.jsx("p",{className:"git-message error",children:Q}),X&&e.jsxs("p",{className:"git-message success",children:[e.jsx(q,{size:14}),X]}),i&&e.jsxs(e.Fragment,{children:[e.jsxs("section",{className:"git-section",children:[e.jsxs("button",{className:"git-section-toggle",type:"button","aria-expanded":$,onClick:()=>L(t=>!t),children:[e.jsxs("span",{className:"git-section-heading",children:[e.jsx(ze,{size:16}),e.jsxs("span",{children:[e.jsx("strong",{children:s("git.authentication")}),e.jsx("small",{children:i.tokenConfigured?s("git.connectedAs",{login:i.githubLogin}):s("git.authenticationHint")})]})]}),$?e.jsx(ie,{size:16}):e.jsx(ne,{size:16})]}),$&&e.jsxs("div",{className:"git-section-content",children:[e.jsxs("div",{className:"git-token-guidance",children:[e.jsx("strong",{children:s("git.recommendedAccessTitle")}),e.jsx("span",{children:s("git.recommendedAccess")})]}),i.tokenConfigured&&e.jsxs("div",{className:"git-account",children:[e.jsx(W,{size:17}),e.jsx("span",{children:s("git.connectedAs",{login:i.githubLogin})}),e.jsxs("button",{className:"danger-text",disabled:!!a,onClick:he,children:[e.jsx(ke,{size:14}),s("git.removeToken")]})]}),e.jsxs("label",{className:"form-field",children:[i.tokenConfigured?s("git.replaceToken"):s("git.token"),e.jsx("input",{type:"password",autoComplete:"new-password",spellCheck:!1,autoCapitalize:"none",autoCorrect:"off",value:T,placeholder:s("git.tokenPlaceholder"),onChange:t=>k(t.target.value)})]}),e.jsxs("div",{className:"git-inline-actions",children:[e.jsxs("a",{href:"https://github.com/settings/personal-access-tokens/new",target:"_blank",rel:"noreferrer",children:[s("git.createToken"),e.jsx(ae,{size:12})]}),e.jsxs("button",{disabled:!!a||T.trim().length<20,onClick:de,children:[a==="token"&&e.jsx(p,{className:"spin",size:13}),s("git.saveToken")]})]})]})]}),e.jsxs("section",{className:"git-section",children:[e.jsxs("button",{className:"git-section-toggle",type:"button","aria-expanded":P,onClick:()=>A(t=>!t),children:[e.jsxs("span",{className:"git-section-heading",children:[e.jsx(W,{size:16}),e.jsxs("span",{children:[e.jsx("strong",{children:s("git.repository")}),e.jsx("small",{children:i.remoteUrl?i.repositoryName??i.remoteUrl:i.initialized?s("git.localReady"):s("git.localPending")})]})]}),P?e.jsx(ie,{size:16}):e.jsx(ne,{size:16})]}),P&&e.jsx("div",{className:"git-section-content",children:i.remoteUrl?e.jsxs("div",{className:"git-repository-card",children:[e.jsxs("div",{children:[e.jsx("strong",{children:i.repositoryName??s("git.origin")}),e.jsxs("small",{children:[i.branch??s("git.detachedAt",{revision:i.latestCommit?.shortSha??"HEAD"})," · ",i.dirty?s("git.changedFiles",{count:i.changedFiles}):s("git.clean")]})]}),i.repositoryHtmlUrl&&e.jsxs("a",{href:i.repositoryHtmlUrl,target:"_blank",rel:"noreferrer",children:[e.jsx(ae,{size:14}),s("git.openGitHub")]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("label",{className:"form-field",children:[s("git.repositoryName"),e.jsx("input",{value:F,onChange:t=>K(t.target.value)})]}),e.jsxs("label",{className:"checkbox-field",children:[e.jsx("input",{type:"checkbox",checked:_,onChange:t=>ce(t.target.checked)}),s("git.privateRepository")]}),e.jsxs("button",{className:"git-primary-action",disabled:!!a||!i.tokenConfigured||!F.trim(),onClick:ge,children:[a==="repository"?e.jsx(p,{className:"spin",size:14}):e.jsx(W,{size:14}),s("git.createRepository")]})]})})]}),i.initialized&&e.jsxs("section",{className:"git-section",children:[e.jsxs("div",{className:"git-section-heading",children:[e.jsx(oe,{size:16}),e.jsxs("div",{children:[e.jsx("strong",{children:s("git.commitAndPush")}),e.jsx("small",{children:i.branch?s("git.identity",{username:o.ownerUsername}):s("git.detachedHead")})]})]}),e.jsxs("label",{className:"form-field",children:[s("git.commitMessage"),e.jsx("textarea",{rows:3,value:D,placeholder:s("git.commitPlaceholder"),onChange:t=>Z(t.target.value)})]}),e.jsxs("div",{className:"git-action-row",children:[e.jsxs("button",{title:i.dirty?void 0:s("git.noChangesToCommit"),disabled:!!a||!i.branch||!i.dirty||!D.trim(),onClick:ue,children:[a==="commit"?e.jsx(p,{className:"spin",size:14}):e.jsx(oe,{size:14}),s("git.commit")]}),e.jsxs("button",{disabled:!!a||!i.branch||!i.tokenConfigured||!i.remoteUrl||!i.latestCommit,onClick:me,children:[a==="push"?e.jsx(p,{className:"spin",size:14}):e.jsx(we,{size:14}),s("git.push"),i.ahead>0&&e.jsx("span",{className:"git-count",children:i.ahead})]}),e.jsxs("button",{disabled:!!a||!i.latestCommit,onClick:()=>{I()},children:[a==="diff"?e.jsx(p,{className:"spin",size:14}):e.jsx(G,{size:14}),s("git.workingDiff")]}),e.jsxs("button",{className:"git-discard-button",title:i.restorable?s("git.discardChanges"):s("git.noChangesToDiscard"),disabled:!!a||!i.latestCommit||!i.restorable,onClick:()=>v(!0),children:[e.jsx(be,{size:14}),s("git.discardChanges")]}),!i.branch&&e.jsxs("button",{disabled:!!a,onClick:()=>{U(!1),j("branch")},children:[e.jsx(q,{size:14}),s("git.returnToBranch",{branch:i.defaultBranch})]}),e.jsxs("button",{disabled:!!a,onClick:()=>{d("refresh",z)},children:[e.jsx(Ee,{className:a==="refresh"?"spin":"",size:14}),s("git.refresh")]})]})]}),b&&e.jsxs("section",{ref:O,className:`git-section git-diff-section${u?" is-fullscreen":""}`,children:[e.jsxs("div",{className:"git-diff-heading",children:[e.jsxs("div",{className:"git-section-heading",children:[e.jsx(G,{size:16}),e.jsxs("div",{children:[e.jsx("strong",{children:s("git.diffTitle")}),e.jsxs("small",{children:[b.title,b.truncated?` · ${s("git.diffTruncated")}`:""]})]})]}),e.jsxs("div",{className:"git-diff-controls",children:[e.jsxs("div",{className:"git-diff-font-controls",role:"group","aria-label":s("git.diffFontSize"),children:[e.jsx("button",{type:"button",className:"git-diff-font-button",disabled:w<=8,title:s("git.diffFontDecrease"),"aria-label":s("git.diffFontDecrease"),onClick:()=>Y(t=>Math.max(8,t-1)),children:e.jsx(ve,{size:14})}),e.jsxs("span",{className:"git-diff-font-value","aria-live":"polite",children:[w,"px"]}),e.jsx("button",{type:"button",className:"git-diff-font-button",disabled:w>=24,title:s("git.diffFontIncrease"),"aria-label":s("git.diffFontIncrease"),onClick:()=>Y(t=>Math.min(24,t+1)),children:e.jsx(Ce,{size:14})})]}),e.jsx("button",{type:"button",className:"git-diff-fullscreen",title:s(u?"git.exitFullscreenDiff":"git.fullscreenDiff"),"aria-label":s(u?"git.exitFullscreenDiff":"git.fullscreenDiff"),onClick:()=>{fe()},children:u?e.jsx(Se,{size:15}):e.jsx(Ne,{size:15})})]})]}),e.jsx(Fe,{content:b.diff,empty:s("git.noChanges"),fontSize:w})]}),i.initialized&&e.jsxs("section",{className:"git-section",children:[e.jsxs("div",{className:"git-section-heading",children:[e.jsx(q,{size:16}),e.jsxs("div",{children:[e.jsx("strong",{children:s("git.history")}),e.jsx("small",{children:s("git.historyHint")})]})]}),e.jsxs("div",{className:"git-history",children:[J.map(t=>e.jsxs("article",{children:[e.jsx("code",{children:t.shortSha}),e.jsxs("div",{children:[e.jsx("strong",{children:t.message}),e.jsxs("small",{children:[t.authorName," · ",new Date(t.authoredAt).toLocaleString(E.resolvedLanguage)]})]}),e.jsxs("span",{children:[e.jsx("button",{title:s("git.viewCommitDiff"),disabled:!!a,onClick:()=>{I(t.sha)},children:e.jsx(G,{size:14})}),e.jsx("button",{title:s("git.checkoutVersion"),disabled:!!a,onClick:()=>{U(!1),j(t)},children:e.jsx(Te,{size:14})})]})]},t.sha)),J.length===0&&e.jsx("p",{className:"muted",children:s("git.noCommits")})]})]})]})]})}),e.jsx(H,{open:!!f,title:s(f==="branch"?"git.returnTitle":"git.checkoutTitle"),description:f==="branch"?s("git.returnDescription",{branch:i?.defaultBranch??"main"}):s("git.checkoutDescription",{revision:f?.shortSha??"",message:f?.message??""}),onOpenChange:t=>{t||j(null)},footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>j(null),children:s("common.cancel")}),e.jsx("button",{className:R?"danger":"primary",onClick:xe,children:s("git.checkout")})]}),children:e.jsxs("label",{className:"git-force-checkout",children:[e.jsx("input",{type:"checkbox",checked:R,onChange:t=>U(t.target.checked)}),e.jsxs("span",{children:[e.jsx("strong",{children:s("git.forceCheckout")}),e.jsx("small",{children:s("git.forceCheckoutDescription")})]})]})}),e.jsx(H,{open:le,title:s("git.discardTitle"),description:s("git.discardDescription"),onOpenChange:v,footer:e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>v(!1),children:s("common.cancel")}),e.jsx("button",{className:"danger",onClick:pe,children:s("git.discardConfirm")})]}),children:e.jsx(e.Fragment,{})})]})}function Fe({content:g,empty:o,fontSize:y}){return g.trim()?e.jsx("pre",{className:"git-diff",style:{fontSize:`${y}px`},children:g.split(`
|
|
2
|
-
`).map((r,s)=>{const E=r.startsWith("+")&&!r.startsWith("+++")?"addition":r.startsWith("-")&&!r.startsWith("---")?"deletion":r.startsWith("@@")?"hunk":r.startsWith("diff ")?"header":"";return e.jsxs("span",{className:E,children:[r,`
|
|
3
|
-
`]},s)})}):e.jsx("div",{className:"git-diff-empty",children:o})}function re(g){return g.trim().replace(/\s+/g,"-").replace(/[^A-Za-z0-9._-]/g,"-").replace(/-+/g,"-").replace(/^[.-]+|[.-]+$/g,"").slice(0,100)||"texlite-project"}export{Ue as GitDialog};
|