-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
426 lines (390 loc) · 21.8 KB
/
index.html
File metadata and controls
426 lines (390 loc) · 21.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" sizes="any" />
<title>Source Printer</title>
</head>
<body class="bg-base-100 text-base-content">
<main id="landing" class="relative flex min-h-screen items-center justify-center px-6">
<div class="flex w-full max-w-xl flex-col items-center gap-6 text-center">
<div class="space-y-3">
<img src="/logo.png" alt="Source Printer" class="mx-auto w-auto" />
<p class="text-sm text-base-content/70">Select a zip file with your student projects to preview <span class="font-semibold">locally</span>. Embedded <span class="font-semibold">.umz</span> archives (Unimozer/Java) are supported.</p>
</div>
<div class="flex w-full flex-col items-center gap-2">
<input id="zip-input" type="file" accept=".zip" class="file-input file-input-bordered w-full max-w-md" />
<p id="landing-meta" class="text-xs text-base-content/60">No file selected.</p>
</div>
<div class="flex flex-wrap justify-center gap-3">
<button id="landing-upload" class="btn btn-primary" disabled>Preview</button>
<button id="landing-demo" class="btn btn-outline">Demo</button>
</div>
<p id="landing-status" class="text-xs text-base-content/60"></p>
</div>
<div class="absolute bottom-6 right-6 flex items-center gap-4">
<a
href="https://github.com/haan/sourceprinter"
class="link link-primary text-xs"
target="_blank"
rel="noreferrer"
>GitHub</a>
<a href="#help" data-modal-link="help" class="link link-primary text-xs">Help</a>
<a href="#privacy" data-modal-link="privacy" class="link link-primary text-xs">Data privacy</a>
</div>
</main>
<input type="checkbox" id="privacy-modal" class="modal-toggle" />
<div class="modal" role="dialog">
<div class="modal-box max-h-[85vh] w-11/12 max-w-4xl">
<div class="flex items-center justify-between gap-4">
<h2 class="text-lg font-semibold">Data privacy</h2>
<label for="privacy-modal" class="btn btn-ghost btn-sm">Close</label>
</div>
<div class="mt-4 space-y-6 text-sm leading-relaxed text-base-content/80">
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Summary</h3>
<p>
The Source Printer processes the zip file you upload solely to generate the PDF documents you request.
The content of uploaded files is not stored, shared, distributed, or processed for any other purpose.
Files are handled transiently and are deleted immediately after the PDF output has been produced.
</p>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">How processing works</h3>
<ol class="list-decimal space-y-2 pl-5">
<li>
Your browser reads the zip file locally to display a preview of source files. This preview happens entirely on
your device and is not uploaded until you click "Generate PDF files" and confirm.
</li>
<li>
When you confirm "Generate PDF files", the zip file, your selected settings, and the list of files you
selected are sent to the server over an encrypted HTTPS connection.
</li>
<li>
The server saves the upload into a temporary working directory, extracts source files, applies the
selected filters, and renders highlighted pages into PDF format.
</li>
<li>
The server streams the generated PDF (or a zip of per-project PDFs) directly back to your browser.
</li>
<li>
Immediately after the response is produced, the temporary working directory and uploaded files are deleted.
</li>
</ol>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">No secondary use of uploaded content</h3>
<p>
Uploaded source code is processed exclusively for the purpose of generating the PDF output you requested.
It is not analyzed for analytics, not used to train models, and not disclosed to third parties.
No backups of uploaded content are made.
</p>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Technical handling and retention</h3>
<ul class="list-disc space-y-2 pl-5">
<li>Temporary files exist only for the duration of the request and are deleted once processing completes.</li>
<li>Generated PDFs are streamed to you and are not stored on the server after delivery.</li>
<li>Processing is performed on the server itself; files are not uploaded to external processing providers.</li>
<li>Selected settings are stored locally in your browser (localStorage) to remember your preferences.</li>
<li>
Standard web server access logs may record request metadata (such as IP address, timestamp, and URL) for
security and operational purposes. These logs do not contain the content of uploaded files.
</li>
</ul>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Hosting location</h3>
<p>
The server is hosted in the data center of a public school in Luxembourg. Processing occurs on this server,
and uploaded content does not leave this environment.
</p>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Security</h3>
<p>
Transport security is provided through HTTPS. The application is designed to keep processing isolated to the
request lifecycle and to delete all temporary data immediately after completion.
</p>
</section>
</div>
</div>
<label class="modal-backdrop" for="privacy-modal">Close</label>
</div>
<input type="checkbox" id="help-modal" class="modal-toggle" />
<div class="modal" role="dialog">
<div class="modal-box max-h-[85vh] w-11/12 max-w-3xl">
<div class="flex items-center justify-between gap-4">
<h2 class="text-lg font-semibold">Help: zip structure</h2>
<label for="help-modal" class="btn btn-ghost btn-sm">Close</label>
</div>
<div class="mt-4 space-y-6 text-sm leading-relaxed text-base-content/80">
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Required structure</h3>
<p>
The zip file must contain one or more project folders. Each project folder becomes the project name in the
preview and PDFs.
</p>
<p>
Source code files can be in any subfolder under each project. Common file types are supported
(e.g. <span class="font-medium">.java</span>, <span class="font-medium">.py</span>,
<span class="font-medium">.js</span>, <span class="font-medium">.ts</span>,
<span class="font-medium">.c</span>, <span class="font-medium">.cpp</span> and many more).
Binary and non-source files are ignored.
</p>
<p>
If your projects are nested below the top level, set the <span class="font-medium">Project folder level</span>
slider in the Input section to match where the project folders live (1 = top level, 2 = one folder deeper).
</p>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Example structure</h3>
<div class="rounded-box border border-base-300 bg-base-200 p-4 font-mono text-xs">
<div>my-upload.zip</div>
<div class="pl-4">ProjectAlpha/</div>
<div class="pl-8">src/</div>
<div class="pl-12">Main.java</div>
<div class="pl-12">Utils.java</div>
<div class="pl-4">ProjectBeta/</div>
<div class="pl-8">app/</div>
<div class="pl-12">App.java</div>
</div>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Upload limits</h3>
<ul class="list-disc space-y-2 pl-5">
<li>Maximum zip size: 50 MB.</li>
<li>Maximum total extracted size: 50 MB.</li>
<li>Maximum size per embedded .umz: 10 MB.</li>
<li>Maximum size per source file: 2 MB.</li>
<li>Maximum number of files: 2,000.</li>
</ul>
</section>
<section class="space-y-3">
<h3 class="text-base font-semibold text-base-content">Notes</h3>
<ul class="list-disc space-y-2 pl-5">
<li>The folder name at the selected project level is used as the project name.</li>
<li>Embedded <span class="font-medium">.umz</span> files (Unimozer/Java) are treated as zip containers and scanned for source files.</li>
<li>Source files found in a .umz appear with a nested path (for example <span class="font-mono">ProjectA/A.umz/src/Order.java</span>).</li>
<li>Nested .umz files inside another .umz are ignored.</li>
<li>Hidden/macOS metadata files are ignored (for example entries under <span class="font-mono">__MACOSX</span> or files starting with <span class="font-mono">.</span>).</li>
<li>Use the checkbox next to a file to exclude it from the generated PDFs.</li>
<li>Binary and non-source files (images, compiled outputs, etc.) are ignored.</li>
</ul>
</section>
</div>
</div>
<label class="modal-backdrop" for="help-modal">Close</label>
</div>
<input type="checkbox" id="reset-modal" class="modal-toggle" />
<div class="modal" role="dialog">
<div class="modal-box max-w-sm">
<h2 class="text-lg font-semibold">Reset settings?</h2>
<p class="mt-2 text-sm text-base-content/70">
This will restore all settings to their defaults.
</p>
<div class="mt-4 flex justify-end gap-2">
<label for="reset-modal" class="btn btn-ghost btn-sm">Cancel</label>
<button id="reset-settings" class="btn btn-primary btn-sm">Reset</button>
</div>
</div>
<label class="modal-backdrop" for="reset-modal">Close</label>
</div>
<input type="checkbox" id="confirm-download-modal" class="modal-toggle" />
<div class="modal" role="dialog">
<div class="modal-box max-w-md">
<h2 class="text-lg font-semibold">Send zip file to server?</h2>
<p class="mt-2 text-sm text-base-content/70">
Confirming will send the selected zip and your settings to the server to generate the PDFs.
See the <a href="#privacy" data-modal-link="privacy" class="link link-primary">data privacy</a> note.
</p>
<div class="mt-4 flex justify-end gap-2">
<label for="confirm-download-modal" class="btn btn-ghost btn-sm">Cancel</label>
<button id="confirm-download" class="btn btn-primary btn-sm">Confirm</button>
</div>
</div>
<label class="modal-backdrop" for="confirm-download-modal">Close</label>
</div>
<div id="app" class="hidden min-h-screen">
<header class="px-6 pt-6">
<div class="mx-auto flex max-w-7xl items-center">
<img src="/logo.png" alt="Source Printer" class="h-20 w-auto ml-1" />
</div>
</header>
<main class="mx-auto w-full max-w-7xl space-y-6 px-6 pb-10 pt-6">
<section class="space-y-6">
<div class="rounded-box border border-base-300 bg-base-100 p-5 shadow">
<div class="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.25em] text-base-content/70">
Uploaded zip
</p>
<p id="zip-meta" class="text-xs text-base-content/60">No file selected.</p>
</div>
<div class="flex items-center gap-2">
<input id="zip-input-app" type="file" accept=".zip" class="hidden" />
<button id="change-zip" class="btn btn-xs btn-outline">Change</button>
</div>
</div>
</div>
<div class="rounded-box border border-base-300 bg-base-100 p-5 shadow">
<div class="flex items-center justify-between">
<h2 class="text-sm font-semibold uppercase tracking-[0.2em] text-base-content/70">
Projects
</h2>
<span id="file-count" class="text-xs text-base-content/60">0 files</span>
</div>
<div id="file-list" class="mt-4 max-h-[360px] overflow-x-auto overflow-y-auto text-sm text-base-content/80">
<p class="text-xs text-base-content/60">Upload a zip to see your source files.</p>
</div>
</div>
</section>
<div class="grid gap-6 lg:grid-cols-[360px_minmax(0,1fr)]">
<section class="rounded-box border border-base-300 bg-base-100 p-5 shadow">
<div class="space-y-3">
<div class="flex justify-end">
<label for="reset-modal" class="btn btn-xs btn-outline cursor-pointer">Reset to defaults</label>
</div>
<div class="collapse collapse-arrow bg-base-200">
<input type="radio" name="settings-accordion" />
<div class="collapse-title text-sm font-semibold">Input</div>
<div class="collapse-content">
<div class="grid gap-3">
<label class="form-control">
<span class="label-text text-sm font-medium">Project folder level</span>
<input id="project-level" type="range" min="1" max="3" step="1" value="1" class="range range-primary" />
<div class="mt-1 flex w-full justify-between px-2 text-xs text-base-content/60">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
</label>
</div>
</div>
</div>
<div class="collapse collapse-arrow bg-base-200">
<input type="radio" name="settings-accordion" checked />
<div class="collapse-title text-sm font-semibold">Design</div>
<div class="collapse-content">
<div class="grid gap-3">
<label class="form-control">
<span class="label-text text-sm font-medium">Font size</span>
<input id="font-size" type="range" min="9" max="18" value="12" class="range range-primary" />
<span id="font-size-value" class="mt-1 text-xs text-base-content/70">12 px</span>
</label>
<label class="form-control">
<span class="label-text text-sm font-medium">Line height</span>
<input id="line-height" type="range" min="1.2" max="2" step="0.05" value="1.5" class="range range-primary" />
<span id="line-height-value" class="mt-1 text-xs text-base-content/70">1.5</span>
</label>
<div class="grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-2">
<span class="label-text text-sm font-medium">Tabs to spaces</span>
<input id="tabs-to-spaces-toggle" type="checkbox" class="toggle toggle-primary" />
</div>
<label class="form-control">
<span class="label-text text-sm font-medium">Color scheme</span>
<select id="theme-select" class="select select-bordered w-full"></select>
</label>
<label class="form-control">
<span class="label-text text-sm font-medium">Font family</span>
<select id="font-select" class="select select-bordered w-full"></select>
</label>
</div>
</div>
</div>
<div class="collapse collapse-arrow bg-base-200">
<input type="radio" name="settings-accordion" />
<div class="collapse-title text-sm font-semibold">Filter</div>
<div class="collapse-content">
<div class="grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-2">
<span class="label-text">Remove comments</span>
<input id="filter-comments-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">Collapse blank lines</span>
<input id="filter-blanklines-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
</div>
<div id="language-filter-section"></div>
</div>
</div>
<div class="collapse collapse-arrow bg-base-200">
<input type="radio" name="settings-accordion" />
<div class="collapse-title text-sm font-semibold">Output</div>
<div class="collapse-content">
<div class="grid grid-cols-[1fr_auto] items-center gap-x-3 gap-y-2">
<span class="label-text">Single continuous PDF</span>
<input id="output-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">Project name in header</span>
<input id="header-project-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">File name in header</span>
<input id="header-file-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">Full path in header</span>
<input id="header-path-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">Page numbers in footer</span>
<input id="footer-page-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">Show line numbers</span>
<input id="line-numbers-toggle" type="checkbox" class="toggle toggle-primary justify-self-end" />
<span class="label-text">Pad to page multiple of</span>
<select id="page-break-select" class="select select-bordered select-sm w-full">
<option value="1">1</option>
<option value="2">2</option>
<option value="4">4</option>
<option value="8">8</option>
</select>
</div>
</div>
</div>
</div>
<div class="mt-4">
<button id="download-btn" class="btn btn-primary w-full" disabled>
<span id="download-spinner" class="loading loading-spinner hidden"></span>
<span>Generate PDF files</span>
</button>
<p id="status" class="mt-2 text-xs text-base-content/70"></p>
<div id="progress-wrap" class="mt-3 flex justify-center hidden">
<div
id="progress-ring"
class="radial-progress text-primary"
style="--value:0; --size:4.5rem; --thickness:4px;"
role="progressbar"
aria-label="Render progress"
>
<span id="progress-value" class="text-xs font-medium">0%</span>
</div>
</div>
</div>
</section>
<section class="relative rounded-box border border-base-300 bg-base-100 p-6 shadow">
<div class="flex items-center justify-between">
<div>
<p class="text-xs uppercase tracking-[0.3em] text-base-content/70">Preview</p>
<h2 id="preview-title" class="text-2xl font-semibold">Select a file</h2>
</div>
<span id="preview-meta" class="text-xs text-base-content/60"></span>
</div>
<div id="preview-wrapper" class="mt-6 mx-auto rounded-box border border-base-300 bg-white overflow-hidden">
<div id="preview-page-header">
<span id="preview-header-left"></span>
<span id="preview-header-right"></span>
</div>
<pre class="max-h-[68vh] overflow-auto">
<code id="code-block" class="language-plaintext"></code>
</pre>
<div id="preview-page-footer">Page 1</div>
</div>
</section>
</div>
</main>
<div class="fixed bottom-6 right-6 flex items-center gap-4">
<a
href="https://github.com/haan/sourceprinter"
class="link link-primary text-xs"
target="_blank"
rel="noreferrer"
>GitHub</a>
<a href="#help" data-modal-link="help" class="link link-primary text-xs">Help</a>
<a href="#privacy" data-modal-link="privacy" class="link link-primary text-xs">Data privacy</a>
</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>