doc-survival-kit 1.0.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/LICENSE +21 -0
- package/README.md +248 -0
- package/admin.html +329 -0
- package/bin/cli.js +77 -0
- package/diagram.html +234 -0
- package/diagram.js +1572 -0
- package/diagrammes.js +231 -0
- package/i18n/en.js +186 -0
- package/i18n/fr.js +187 -0
- package/i18n/i18n.js +27 -0
- package/images/diagram-overview.png +0 -0
- package/images/img_1774270331723.png +0 -0
- package/index.html +340 -0
- package/liens.js +391 -0
- package/mesLiens.js +66 -0
- package/mesNotes.js +90 -0
- package/notes.js +561 -0
- package/package.json +42 -0
- package/style.css +1460 -0
- package/taches.js +96 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Youssef MEDAGHRI-ALAOUI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# myTasks. myNotes. myLinks. & Diagrams !
|
|
2
|
+
|
|
3
|
+
> A three-column personal productivity dashboard, and a diagramming tool with zero dependencies, zero server, zero security compromises. Available in **French** and **English**.
|
|
4
|
+
|
|
5
|
+
## Security — why this project can be used anywhere
|
|
6
|
+
|
|
7
|
+
This is one of the dashboard's greatest strengths. Here is why it poses **no risk** in a secure environment:
|
|
8
|
+
|
|
9
|
+
| Criterion | This project |
|
|
10
|
+
| ---------------- | ----------------------------------------------------------------------------- |
|
|
11
|
+
| Network requests | **None** — no CDN, no API, no tracking |
|
|
12
|
+
| External deps | **None** — plain HTML, CSS and Vanilla JavaScript only |
|
|
13
|
+
| Server required | **No** — opens directly via `file://` in the browser |
|
|
14
|
+
| Data sent | **Never** — everything stays on your machine (`localStorage` and local files) |
|
|
15
|
+
| Installation | **None** — no executable, no package manager, no admin rights |
|
|
16
|
+
| Auditable code | **Yes** — a handful of readable files, nothing minified or obfuscated |
|
|
17
|
+
|
|
18
|
+
> **In practice**: you can open this on any machine without internet access, or in any environment where installing tools or reaching external services is not possible. It makes no outbound connections, loads nothing from the outside, and stores your data only where you choose.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
## Why this project?
|
|
27
|
+
|
|
28
|
+
Some environments have **no internet access** or don't allow installing tools: no task-tracking software, no CDN, nothing from the outside.
|
|
29
|
+
|
|
30
|
+
Yet your productivity depends on your ability to **log your tasks**, your **notes** and your **useful links** somewhere — and find them again each morning.
|
|
31
|
+
|
|
32
|
+
This project solves that problem: a **single HTML file** you drop on your desktop that works in any browser, even offline.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## The three panels
|
|
37
|
+
|
|
38
|
+
### myTasks. — Task manager
|
|
39
|
+
|
|
40
|
+
Add tasks in an instant, sort them by priority, tick them off as the day goes on.
|
|
41
|
+
|
|
42
|
+
- Three priority levels: **Urgent**, **Normal**, **Later**
|
|
43
|
+
- Status filters: All, To do, Done, Urgent, Normal, Later
|
|
44
|
+
- Checkbox to mark a task as complete
|
|
45
|
+
- Individual deletion
|
|
46
|
+
|
|
47
|
+
### myNotes. — Structured notepad
|
|
48
|
+
|
|
49
|
+
Everything you need to remember, organised as notes made of freely stackable blocks.
|
|
50
|
+
|
|
51
|
+
- Five block types per note:
|
|
52
|
+
- **Title** — short bold text to structure the note
|
|
53
|
+
- **Text** — free paragraph
|
|
54
|
+
- **Code** — monospace block with grey background (commands, regex, snippets…)
|
|
55
|
+
- **List** — bullet points
|
|
56
|
+
- **Table** — columns separated by `|`, first line = headers
|
|
57
|
+
- Each note has a customisable colour
|
|
58
|
+
- Notes are **collapsed by default** — click the chevron to expand; use the toolbar button to expand/collapse all at once
|
|
59
|
+
- Add, edit and delete notes and blocks in edit mode
|
|
60
|
+
|
|
61
|
+
### myLinks. — Useful link directory
|
|
62
|
+
|
|
63
|
+
Your links organised by category, accessible in one click.
|
|
64
|
+
|
|
65
|
+
- Customisable categories with a colour of your choice
|
|
66
|
+
- Categories are **collapsed by default** — click the chevron to expand; use the toolbar button to expand/collapse all at once
|
|
67
|
+
- Displayed with name and description
|
|
68
|
+
- Add, edit and delete in edit mode
|
|
69
|
+
|
|
70
|
+
### myDiagrams. — Diagram editor
|
|
71
|
+
|
|
72
|
+
A lightweight SVG diagram editor accessible via the diagram icon (top-right of the dashboard).
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
#### Shapes
|
|
77
|
+
|
|
78
|
+
Six shape types are available from the toolbar:
|
|
79
|
+
|
|
80
|
+
| Shape | Description |
|
|
81
|
+
| ----------------- | --------------------------------------------------------- |
|
|
82
|
+
| Rectangle | Standard box with slightly rounded corners |
|
|
83
|
+
| Rounded rectangle | Pill-shaped box |
|
|
84
|
+
| Database | Cylinder — represents a data store |
|
|
85
|
+
| External service | Solid ellipse — represents a third-party or cloud service |
|
|
86
|
+
| Free text | Label without a background |
|
|
87
|
+
| Post-it | Sticky note with a folded corner, multi-line text |
|
|
88
|
+
|
|
89
|
+
#### Arrows
|
|
90
|
+
|
|
91
|
+
- Draw arrows by clicking **source → target** with the arrow tool, or by **dragging from a connection dot** on any shape
|
|
92
|
+
- The label input opens automatically after creating an arrow
|
|
93
|
+
- **Double-click** an arrow (or use the ✎ button) to edit its label
|
|
94
|
+
|
|
95
|
+
#### Text editing
|
|
96
|
+
|
|
97
|
+
- **Double-click** a shape (or use the ✎ button) to edit its text inline
|
|
98
|
+
- For `rect`, `rounded`, `db`, `cloud` and `postit` shapes, a **transparent textarea** is overlaid directly on the shape — text wraps automatically as you type
|
|
99
|
+
- The text input for the `db` cylinder is positioned in the **body only**, below the top cap
|
|
100
|
+
|
|
101
|
+
#### Text formatting palette
|
|
102
|
+
|
|
103
|
+
When a shape is selected, a formatting palette appears. From left to right:
|
|
104
|
+
|
|
105
|
+
| Control | Effect |
|
|
106
|
+
| ------------- | -------------------------------------------------------------------------------------------------- |
|
|
107
|
+
| 6 colour dots | Apply a theme colour to the shape |
|
|
108
|
+
| ✎ | Open the inline text editor |
|
|
109
|
+
| `Aa+` / `Aa−` | Increase / decrease font size (range: 8–28 px) |
|
|
110
|
+
| ← / ↔ / → | Horizontal text alignment: left / centre / right |
|
|
111
|
+
| ↑ / ↕ / ↓ | Vertical text alignment: top / middle / bottom |
|
|
112
|
+
| Hollow drop | Copy the **font size** from another shape — click the button then click the source shape |
|
|
113
|
+
| Filled drop | Copy the **full style** from another shape (font size, colour, shape type, dimensions, alignments) |
|
|
114
|
+
|
|
115
|
+
> The style copy (filled drop) works with multi-selection: select several shapes, activate the drop, click the source — all selected shapes are updated at once.
|
|
116
|
+
|
|
117
|
+
#### Text wrapping
|
|
118
|
+
|
|
119
|
+
Text in `rect`, `rounded`, `db`, `cloud` and `postit` shapes wraps automatically to fit the shape width. Resizing a shape immediately re-flows the text. The font size set via `Aa+`/`Aa−` is also taken into account when computing line breaks.
|
|
120
|
+
|
|
121
|
+
#### Zoom per diagram
|
|
122
|
+
|
|
123
|
+
Each diagram remembers its own zoom level. Switching from one diagram to another restores the zoom you were using last time — stored in `localStorage` separately from the diagram data.
|
|
124
|
+
|
|
125
|
+
#### Lock per diagram
|
|
126
|
+
|
|
127
|
+
The lock button (🔓/🔒) in the toolbar freezes the diagram: all canvas interactions (selection, tools, keyboard shortcuts) are disabled and any click simply pans the view. The lock state is saved per diagram in `localStorage` and restored when you switch back to it.
|
|
128
|
+
|
|
129
|
+
#### Navigation
|
|
130
|
+
|
|
131
|
+
- The ☰ button opens the diagram list panel — clicking a diagram name switches to it **and closes the panel automatically**
|
|
132
|
+
- Diagram names **wrap to the next line** if they are too long — nothing is truncated
|
|
133
|
+
- Diagrams can be **reordered by drag & drop** in the panel: grab the `⠿` handle on the left of any item, drag it up or down, and a dashed orange line shows exactly where it will land
|
|
134
|
+
- The `+ New` button creates a new diagram
|
|
135
|
+
- The ← button in the top-right returns to the main dashboard
|
|
136
|
+
|
|
137
|
+
#### Saving
|
|
138
|
+
|
|
139
|
+
- Saves directly to `diagrammes.js` on disk via the File System Access API (same mechanism as notes and links)
|
|
140
|
+
- The green **save** button appears in the toolbar whenever the in-memory data differs from the saved file
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Data persistence
|
|
145
|
+
|
|
146
|
+
Everything is saved in the browser's `localStorage` — your content survives browser restarts.
|
|
147
|
+
|
|
148
|
+
To avoid losing data when you clear the cache or switch machines, each panel has a **"save changes"** button that overwrites the source file (`mesLiens.js` or `mesNotes.js`) directly on your disk, using the **File System Access API** (Chrome and Edge Chromium only).
|
|
149
|
+
|
|
150
|
+
> **First save**: a modal asks you to select the project folder. The file is then updated directly on every subsequent save, with no dialog.
|
|
151
|
+
|
|
152
|
+
## Administration page
|
|
153
|
+
|
|
154
|
+
The ⚙ icon in the top-right corner of the dashboard opens `admin.html`. It lets you:
|
|
155
|
+
|
|
156
|
+
- **Choose the language** — switch between Français and English (saved in localStorage)
|
|
157
|
+
- **Clear localStorage** — resets to the default data from `mesLiens.js` and `mesNotes.js` on next load
|
|
158
|
+
- **Delete IndexedDB** — clears the stored file handle; the next save will ask you to select the folder again
|
|
159
|
+
|
|
160
|
+
The two reset actions are independent, can be checked separately, and are executed via a single button. The page explains the consequences before acting.
|
|
161
|
+
|
|
162
|
+
## Internationalisation
|
|
163
|
+
|
|
164
|
+
The interface is available in **French** (default) and **English**. The language is chosen from the administration page and stored in `localStorage`.
|
|
165
|
+
|
|
166
|
+
Translations live in the `i18n/` folder:
|
|
167
|
+
|
|
168
|
+
| File | Role |
|
|
169
|
+
| -------------- | -------------------------------------------------------------------------- |
|
|
170
|
+
| `i18n/fr.js` | French translations (`var i18n_fr`) |
|
|
171
|
+
| `i18n/en.js` | English translations (`var i18n_en`) |
|
|
172
|
+
| `i18n/i18n.js` | Engine: reads `localStorage["lang"]`, exposes `window.t` and `applyI18n()` |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Quick start
|
|
177
|
+
|
|
178
|
+
### Via npx (recommended)
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npx doc-survival-kit
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Creates a `doc-survival-kit/` folder in the current directory and opens the application automatically in the browser. Subsequent runs simply open the application without overwriting anything.
|
|
185
|
+
|
|
186
|
+
> Requires Node.js >= 16.7. Use Chrome or Edge for file saving.
|
|
187
|
+
|
|
188
|
+
### Without any tool
|
|
189
|
+
|
|
190
|
+
1. Copy the following files and folder into a new directory:
|
|
191
|
+
|
|
192
|
+
- `index.html`
|
|
193
|
+
- `admin.html`
|
|
194
|
+
- `diagram.html`
|
|
195
|
+
- `diagram.js`
|
|
196
|
+
- `diagrammes.js`
|
|
197
|
+
- `liens.js`
|
|
198
|
+
- `mesLiens.js`
|
|
199
|
+
- `mesNotes.js`
|
|
200
|
+
- `notes.js`
|
|
201
|
+
- `style.css`
|
|
202
|
+
- `taches.js`
|
|
203
|
+
- `i18n/` (entire folder)
|
|
204
|
+
|
|
205
|
+
2. Open `index.html` in Chrome or Edge
|
|
206
|
+
3. That's it.
|
|
207
|
+
|
|
208
|
+
Sample content is already present in each panel to give you an idea of what you can put there.
|
|
209
|
+
|
|
210
|
+
### Manually
|
|
211
|
+
|
|
212
|
+
1. Clone or download this repository
|
|
213
|
+
2. Open `index.html` in Chrome or Edge
|
|
214
|
+
3. That's it.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
git clone https://github.com/ymedaghri/doc-survival-kit.git
|
|
218
|
+
cd doc-survival-kit
|
|
219
|
+
open index.html # macOS
|
|
220
|
+
# or
|
|
221
|
+
start index.html # Windows
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Tech stack
|
|
227
|
+
|
|
228
|
+
| Technology | Detail |
|
|
229
|
+
| ------------------ | ------------------------------------------------------- |
|
|
230
|
+
| HTML | Semantic structure, no framework |
|
|
231
|
+
| CSS | Separate styles in `style.css`, no framework |
|
|
232
|
+
| JavaScript | Vanilla, no third-party library |
|
|
233
|
+
| Local storage | Browser `localStorage` |
|
|
234
|
+
| File storage | File System Access API (`showDirectoryPicker`) |
|
|
235
|
+
| Handle persistence | `IndexedDB` — file handle is remembered across sessions |
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Author
|
|
240
|
+
|
|
241
|
+
**Youssef MEDAGHRI-ALAOUI**
|
|
242
|
+
[craftskillz.com](https://www.craftskillz.com/posts/stay-secure-and-productive)
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
This project is distributed under the **MIT** licence — you are free to use, modify and redistribute it, including in commercial projects, provided you retain the original author credit.
|
package/admin.html
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="fr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title data-i18n="page_title_admin">
|
|
7
|
+
Administration — doc-survival-kit
|
|
8
|
+
</title>
|
|
9
|
+
<link rel="stylesheet" href="style.css" />
|
|
10
|
+
<style>
|
|
11
|
+
.admin-shell {
|
|
12
|
+
max-width: 560px;
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
padding: 60px 36px 80px;
|
|
15
|
+
}
|
|
16
|
+
.admin-back {
|
|
17
|
+
position: fixed;
|
|
18
|
+
top: 16px;
|
|
19
|
+
right: 20px;
|
|
20
|
+
font-size: 1.4rem;
|
|
21
|
+
color: #78716c;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
background: #f5f5f4;
|
|
24
|
+
border: 1px solid #e7e5e4;
|
|
25
|
+
border-radius: 8px;
|
|
26
|
+
width: 40px;
|
|
27
|
+
height: 40px;
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
justify-content: center;
|
|
31
|
+
transition:
|
|
32
|
+
background 0.15s,
|
|
33
|
+
color 0.15s;
|
|
34
|
+
line-height: 1;
|
|
35
|
+
}
|
|
36
|
+
.admin-back:hover {
|
|
37
|
+
background: #292524;
|
|
38
|
+
color: #fff;
|
|
39
|
+
border-color: #292524;
|
|
40
|
+
}
|
|
41
|
+
.admin-lang-section {
|
|
42
|
+
margin-bottom: 36px;
|
|
43
|
+
}
|
|
44
|
+
.admin-lang-section h2 {
|
|
45
|
+
font-family: "Cascadia Code", "SF Mono", "Consolas", monospace;
|
|
46
|
+
font-size: 0.65rem;
|
|
47
|
+
letter-spacing: 0.12em;
|
|
48
|
+
text-transform: uppercase;
|
|
49
|
+
color: #a8a29e;
|
|
50
|
+
margin-bottom: 12px;
|
|
51
|
+
}
|
|
52
|
+
.admin-lang-options {
|
|
53
|
+
display: flex;
|
|
54
|
+
gap: 8px;
|
|
55
|
+
}
|
|
56
|
+
.btn-lang {
|
|
57
|
+
font-family: "Cascadia Code", "SF Mono", "Consolas", monospace;
|
|
58
|
+
font-size: 0.7rem;
|
|
59
|
+
letter-spacing: 0.08em;
|
|
60
|
+
padding: 8px 20px;
|
|
61
|
+
border-radius: 8px;
|
|
62
|
+
border: 1px solid #e7e5e4;
|
|
63
|
+
background: #fff;
|
|
64
|
+
cursor: pointer;
|
|
65
|
+
transition:
|
|
66
|
+
background 0.15s,
|
|
67
|
+
border-color 0.15s,
|
|
68
|
+
color 0.15s;
|
|
69
|
+
}
|
|
70
|
+
.btn-lang:hover {
|
|
71
|
+
border-color: #f97316;
|
|
72
|
+
background: #fff7ed;
|
|
73
|
+
}
|
|
74
|
+
.btn-lang.active {
|
|
75
|
+
background: #f97316;
|
|
76
|
+
color: #fff;
|
|
77
|
+
border-color: #f97316;
|
|
78
|
+
}
|
|
79
|
+
.admin-intro {
|
|
80
|
+
background: #fff7ed;
|
|
81
|
+
border: 1px solid #fed7aa;
|
|
82
|
+
border-radius: 10px;
|
|
83
|
+
padding: 20px 24px;
|
|
84
|
+
margin-bottom: 36px;
|
|
85
|
+
}
|
|
86
|
+
.admin-intro h2 {
|
|
87
|
+
font-family: "Cascadia Code", "SF Mono", "Consolas", monospace;
|
|
88
|
+
font-size: 0.65rem;
|
|
89
|
+
letter-spacing: 0.12em;
|
|
90
|
+
text-transform: uppercase;
|
|
91
|
+
color: #f97316;
|
|
92
|
+
margin-bottom: 12px;
|
|
93
|
+
}
|
|
94
|
+
.admin-intro p {
|
|
95
|
+
font-size: 0.875rem;
|
|
96
|
+
line-height: 1.65;
|
|
97
|
+
color: #57534e;
|
|
98
|
+
margin-bottom: 10px;
|
|
99
|
+
}
|
|
100
|
+
.admin-intro p:last-child {
|
|
101
|
+
margin-bottom: 0;
|
|
102
|
+
}
|
|
103
|
+
.admin-intro strong {
|
|
104
|
+
color: #292524;
|
|
105
|
+
}
|
|
106
|
+
.admin-actions {
|
|
107
|
+
display: flex;
|
|
108
|
+
flex-direction: column;
|
|
109
|
+
gap: 12px;
|
|
110
|
+
margin-bottom: 32px;
|
|
111
|
+
}
|
|
112
|
+
.admin-check-label {
|
|
113
|
+
display: flex;
|
|
114
|
+
align-items: flex-start;
|
|
115
|
+
gap: 12px;
|
|
116
|
+
padding: 16px 20px;
|
|
117
|
+
border-radius: 10px;
|
|
118
|
+
border: 1px solid #e7e5e4;
|
|
119
|
+
background: #fff;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
transition:
|
|
122
|
+
border-color 0.15s,
|
|
123
|
+
background 0.15s;
|
|
124
|
+
}
|
|
125
|
+
.admin-check-label:hover {
|
|
126
|
+
border-color: #f97316;
|
|
127
|
+
background: #fff7ed;
|
|
128
|
+
}
|
|
129
|
+
.admin-check-label input[type="checkbox"] {
|
|
130
|
+
margin-top: 2px;
|
|
131
|
+
flex-shrink: 0;
|
|
132
|
+
width: 16px;
|
|
133
|
+
height: 16px;
|
|
134
|
+
accent-color: #f97316;
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
}
|
|
137
|
+
.admin-check-text strong {
|
|
138
|
+
display: block;
|
|
139
|
+
font-size: 0.875rem;
|
|
140
|
+
font-weight: 600;
|
|
141
|
+
color: #292524;
|
|
142
|
+
margin-bottom: 3px;
|
|
143
|
+
}
|
|
144
|
+
.admin-check-text span {
|
|
145
|
+
font-size: 0.8rem;
|
|
146
|
+
color: #a8a29e;
|
|
147
|
+
line-height: 1.5;
|
|
148
|
+
}
|
|
149
|
+
.btn-execute {
|
|
150
|
+
font-family: "Cascadia Code", "SF Mono", "Consolas", monospace;
|
|
151
|
+
font-size: 0.65rem;
|
|
152
|
+
letter-spacing: 0.1em;
|
|
153
|
+
text-transform: uppercase;
|
|
154
|
+
padding: 10px 20px;
|
|
155
|
+
border-radius: 8px;
|
|
156
|
+
background: #fef2f2;
|
|
157
|
+
color: #ef4444;
|
|
158
|
+
border: 1px solid #fecaca;
|
|
159
|
+
transition:
|
|
160
|
+
background 0.15s,
|
|
161
|
+
color 0.15s,
|
|
162
|
+
border-color 0.15s;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
}
|
|
165
|
+
.btn-execute:hover {
|
|
166
|
+
background: #ef4444;
|
|
167
|
+
color: #fff;
|
|
168
|
+
border-color: #ef4444;
|
|
169
|
+
}
|
|
170
|
+
.btn-execute:disabled {
|
|
171
|
+
opacity: 0.4;
|
|
172
|
+
cursor: not-allowed;
|
|
173
|
+
}
|
|
174
|
+
.admin-feedback {
|
|
175
|
+
display: none;
|
|
176
|
+
margin-top: 20px;
|
|
177
|
+
padding: 14px 18px;
|
|
178
|
+
border-radius: 8px;
|
|
179
|
+
font-size: 0.875rem;
|
|
180
|
+
line-height: 1.5;
|
|
181
|
+
}
|
|
182
|
+
.admin-feedback.success {
|
|
183
|
+
background: #d1fae5;
|
|
184
|
+
color: #047857;
|
|
185
|
+
border: 1px solid #6ee7b7;
|
|
186
|
+
}
|
|
187
|
+
</style>
|
|
188
|
+
</head>
|
|
189
|
+
<body>
|
|
190
|
+
<a href="index.html" class="admin-back" title="Retour au dashboard">←</a>
|
|
191
|
+
|
|
192
|
+
<div class="admin-shell">
|
|
193
|
+
<h1>admin<span class="accent">.</span></h1>
|
|
194
|
+
<p class="subtitle" data-i18n="admin_subtitle">
|
|
195
|
+
réinitialisation des données
|
|
196
|
+
</p>
|
|
197
|
+
|
|
198
|
+
<!-- ── Sélecteur de langue ── -->
|
|
199
|
+
<div class="admin-lang-section">
|
|
200
|
+
<h2 data-i18n="admin_lang_title">Langue / Language</h2>
|
|
201
|
+
<div class="admin-lang-options">
|
|
202
|
+
<button class="btn-lang" id="btnLangFr" onclick="setLang('fr')">
|
|
203
|
+
Français
|
|
204
|
+
</button>
|
|
205
|
+
<button class="btn-lang" id="btnLangEn" onclick="setLang('en')">
|
|
206
|
+
English
|
|
207
|
+
</button>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<div class="admin-intro">
|
|
212
|
+
<h2 data-i18n="admin_why_title">Pourquoi cette page ?</h2>
|
|
213
|
+
<p data-i18n-html="admin_why_p1">
|
|
214
|
+
L'application stocke tes données à deux endroits dans ton navigateur :
|
|
215
|
+
le <strong>localStorage</strong> (tâches, notes, liens) et l'<strong
|
|
216
|
+
>IndexedDB</strong
|
|
217
|
+
>
|
|
218
|
+
(le handle du fichier pour la sauvegarde directe).
|
|
219
|
+
</p>
|
|
220
|
+
<p data-i18n-html="admin_why_p2">
|
|
221
|
+
Ces données <strong>ne sont pas supprimées</strong> en vidant le cache
|
|
222
|
+
classique ou en fermant le navigateur. Cette page te permet de les
|
|
223
|
+
effacer proprement, par exemple pour repartir d'une installation
|
|
224
|
+
vierge ou résoudre un problème de synchronisation entre le fichier et
|
|
225
|
+
le navigateur.
|
|
226
|
+
</p>
|
|
227
|
+
<p data-i18n-html="admin_why_p3">
|
|
228
|
+
<strong>Attention :</strong> ces actions sont irréversibles. Si tu
|
|
229
|
+
n'as pas sauvegardé tes modifications dans les fichiers
|
|
230
|
+
<code>mesLiens.js</code> et <code>mesNotes.js</code>, tes données
|
|
231
|
+
seront perdues.
|
|
232
|
+
</p>
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div class="admin-actions">
|
|
236
|
+
<label class="admin-check-label">
|
|
237
|
+
<input type="checkbox" id="checkLocalStorage" />
|
|
238
|
+
<div class="admin-check-text">
|
|
239
|
+
<strong data-i18n="admin_ls_label">Effacer le localStorage</strong>
|
|
240
|
+
<span data-i18n-html="admin_ls_desc"
|
|
241
|
+
>Supprime toutes les tâches, notes et liens mémorisés dans le
|
|
242
|
+
navigateur. Au prochain chargement, l'application repart des
|
|
243
|
+
données par défaut contenues dans <code>mesLiens.js</code> et
|
|
244
|
+
<code>mesNotes.js</code>.</span
|
|
245
|
+
>
|
|
246
|
+
</div>
|
|
247
|
+
</label>
|
|
248
|
+
|
|
249
|
+
<label class="admin-check-label">
|
|
250
|
+
<input type="checkbox" id="checkIndexedDB" />
|
|
251
|
+
<div class="admin-check-text">
|
|
252
|
+
<strong data-i18n="admin_idb_label">Supprimer l'IndexedDB</strong>
|
|
253
|
+
<span data-i18n="admin_idb_desc"
|
|
254
|
+
>Efface le handle de fichier mémorisé pour la sauvegarde directe.
|
|
255
|
+
La prochaine sauvegarde te demandera à nouveau de sélectionner le
|
|
256
|
+
dossier du projet, comme lors de la première utilisation.</span
|
|
257
|
+
>
|
|
258
|
+
</div>
|
|
259
|
+
</label>
|
|
260
|
+
</div>
|
|
261
|
+
|
|
262
|
+
<button
|
|
263
|
+
class="btn-execute"
|
|
264
|
+
id="btnExecute"
|
|
265
|
+
disabled
|
|
266
|
+
onclick="executer()"
|
|
267
|
+
data-i18n="admin_execute_btn"
|
|
268
|
+
>
|
|
269
|
+
exécuter les actions sélectionnées
|
|
270
|
+
</button>
|
|
271
|
+
|
|
272
|
+
<div class="admin-feedback" id="adminFeedback"></div>
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
<script src="i18n/fr.js"></script>
|
|
276
|
+
<script src="i18n/en.js"></script>
|
|
277
|
+
<script src="i18n/i18n.js"></script>
|
|
278
|
+
<script>
|
|
279
|
+
var chkLS = document.getElementById("checkLocalStorage");
|
|
280
|
+
var chkIDB = document.getElementById("checkIndexedDB");
|
|
281
|
+
var btn = document.getElementById("btnExecute");
|
|
282
|
+
var feedback = document.getElementById("adminFeedback");
|
|
283
|
+
|
|
284
|
+
// Highlight active language button
|
|
285
|
+
(function () {
|
|
286
|
+
var lang = localStorage.getItem("lang") || "fr";
|
|
287
|
+
document
|
|
288
|
+
.getElementById(lang === "en" ? "btnLangEn" : "btnLangFr")
|
|
289
|
+
.classList.add("active");
|
|
290
|
+
})();
|
|
291
|
+
|
|
292
|
+
function setLang(lang) {
|
|
293
|
+
localStorage.setItem("lang", lang);
|
|
294
|
+
window.location.reload();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function updateBtn() {
|
|
298
|
+
btn.disabled = !chkLS.checked && !chkIDB.checked;
|
|
299
|
+
}
|
|
300
|
+
chkLS.addEventListener("change", updateBtn);
|
|
301
|
+
chkIDB.addEventListener("change", updateBtn);
|
|
302
|
+
|
|
303
|
+
function executer() {
|
|
304
|
+
var messages = [];
|
|
305
|
+
|
|
306
|
+
if (chkLS.checked) {
|
|
307
|
+
localStorage.clear();
|
|
308
|
+
// Restore lang setting so the page stays in the right language
|
|
309
|
+
var lang = window.t === i18n_en ? "en" : "fr";
|
|
310
|
+
localStorage.setItem("lang", lang);
|
|
311
|
+
messages.push(window.t.admin_feedback_ls);
|
|
312
|
+
chkLS.checked = false;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (chkIDB.checked) {
|
|
316
|
+
indexedDB.deleteDatabase("doc-survival-kit-db");
|
|
317
|
+
messages.push(window.t.admin_feedback_idb);
|
|
318
|
+
chkIDB.checked = false;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
updateBtn();
|
|
322
|
+
feedback.textContent =
|
|
323
|
+
messages.join(" ") + " " + window.t.admin_feedback_return;
|
|
324
|
+
feedback.className = "admin-feedback success";
|
|
325
|
+
feedback.style.display = "block";
|
|
326
|
+
}
|
|
327
|
+
</script>
|
|
328
|
+
</body>
|
|
329
|
+
</html>
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { exec } = require("child_process");
|
|
6
|
+
|
|
7
|
+
const DEST_DIR = path.join(process.cwd(), "doc-survival-kit");
|
|
8
|
+
const SRC_DIR = path.join(__dirname, "..");
|
|
9
|
+
const APP_FILES = [
|
|
10
|
+
"index.html",
|
|
11
|
+
"admin.html",
|
|
12
|
+
"diagram.html",
|
|
13
|
+
"style.css",
|
|
14
|
+
"liens.js",
|
|
15
|
+
"taches.js",
|
|
16
|
+
"notes.js",
|
|
17
|
+
"diagram.js",
|
|
18
|
+
];
|
|
19
|
+
const DATA_FILES = ["mesLiens.js", "mesNotes.js", "diagrammes.js"];
|
|
20
|
+
const I18N_FILES = ["i18n/fr.js", "i18n/en.js", "i18n/i18n.js"];
|
|
21
|
+
const IMAGES_FILES = ["images/img_1774270331723.png"];
|
|
22
|
+
|
|
23
|
+
function openBrowser(filePath) {
|
|
24
|
+
const url = "file://" + filePath;
|
|
25
|
+
const cmd =
|
|
26
|
+
process.platform === "win32"
|
|
27
|
+
? `start "" "${url}"`
|
|
28
|
+
: process.platform === "darwin"
|
|
29
|
+
? `open "${url}"`
|
|
30
|
+
: `xdg-open "${url}"`;
|
|
31
|
+
exec(cmd, (err) => {
|
|
32
|
+
if (err) {
|
|
33
|
+
console.log("Ouvre manuellement dans Chrome ou Edge :");
|
|
34
|
+
console.log(filePath);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const htmlFile = path.join(DEST_DIR, "index.html");
|
|
40
|
+
|
|
41
|
+
if (fs.existsSync(DEST_DIR)) {
|
|
42
|
+
console.log("Le dossier doc-survival-kit existe déjà.");
|
|
43
|
+
console.log("Ouverture de l'application...");
|
|
44
|
+
openBrowser(htmlFile);
|
|
45
|
+
} else {
|
|
46
|
+
fs.mkdirSync(DEST_DIR, { recursive: true });
|
|
47
|
+
|
|
48
|
+
// Fichiers app (toujours copiés)
|
|
49
|
+
for (const file of APP_FILES) {
|
|
50
|
+
fs.copyFileSync(path.join(SRC_DIR, file), path.join(DEST_DIR, file));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Fichiers i18n (toujours copiés)
|
|
54
|
+
fs.mkdirSync(path.join(DEST_DIR, "i18n"), { recursive: true });
|
|
55
|
+
for (const file of I18N_FILES) {
|
|
56
|
+
fs.copyFileSync(path.join(SRC_DIR, file), path.join(DEST_DIR, file));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Fichiers i18n (toujours copiés)
|
|
60
|
+
fs.mkdirSync(path.join(DEST_DIR, "images"), { recursive: true });
|
|
61
|
+
for (const file of IMAGES_FILES) {
|
|
62
|
+
fs.copyFileSync(path.join(SRC_DIR, file), path.join(DEST_DIR, file));
|
|
63
|
+
}
|
|
64
|
+
// Fichiers de données (copiés seulement à la création)
|
|
65
|
+
for (const file of DATA_FILES) {
|
|
66
|
+
fs.copyFileSync(path.join(SRC_DIR, file), path.join(DEST_DIR, file));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log("doc-survival-kit créé dans : " + DEST_DIR);
|
|
70
|
+
console.log("");
|
|
71
|
+
console.log("Note : tes données sont sauvegardées dans ce dossier.");
|
|
72
|
+
console.log(" Ouvre toujours le fichier depuis ce même dossier.");
|
|
73
|
+
console.log("");
|
|
74
|
+
console.log("Ouverture de l'application...");
|
|
75
|
+
console.log("(Utilise Chrome ou Edge pour la sauvegarde de fichiers)");
|
|
76
|
+
openBrowser(htmlFile);
|
|
77
|
+
}
|