@compiiile/compiiile 2.2.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.
Files changed (55) hide show
  1. package/.compiiile/public/favicon.png +0 -0
  2. package/.compiiile/src/app.js +5 -0
  3. package/.compiiile/src/components/ClientScript.vue +48 -0
  4. package/.compiiile/src/components/ContentWrapper.vue +288 -0
  5. package/.compiiile/src/components/SlidesContent.vue +56 -0
  6. package/.compiiile/src/components/TableOfContent.vue +65 -0
  7. package/.compiiile/src/components/layout/HamburgerButton.vue +90 -0
  8. package/.compiiile/src/components/layout/TopBar.vue +106 -0
  9. package/.compiiile/src/components/layout/navBar/FilesTree.vue +35 -0
  10. package/.compiiile/src/components/layout/navBar/NavBar.vue +48 -0
  11. package/.compiiile/src/components/layout/navBar/NavListItem.vue +216 -0
  12. package/.compiiile/src/components/searchBar/SearchBar.vue +371 -0
  13. package/.compiiile/src/components/searchBar/SearchResult.vue +98 -0
  14. package/.compiiile/src/env.d.ts +1 -0
  15. package/.compiiile/src/layouts/BaseLayout.astro +38 -0
  16. package/.compiiile/src/layouts/SlidesLayout.astro +12 -0
  17. package/.compiiile/src/layouts/WorkspaceLayout.astro +58 -0
  18. package/.compiiile/src/pages/404.astro +17 -0
  19. package/.compiiile/src/pages/[...path].astro +61 -0
  20. package/.compiiile/src/style/code-theme.scss +30 -0
  21. package/.compiiile/src/style/index.scss +36 -0
  22. package/.compiiile/src/style/layouts.scss +43 -0
  23. package/.compiiile/src/style/print.scss +80 -0
  24. package/.compiiile/src/style/slides.scss +79 -0
  25. package/.compiiile/src/style/texts.scss +92 -0
  26. package/.compiiile/src/style/variables.scss +47 -0
  27. package/.compiiile/src/utils/searchIndex.js +28 -0
  28. package/.compiiile/src/utils/styles.js +9 -0
  29. package/.eslintrc.cjs +15 -0
  30. package/.github/FUNDING.yml +2 -0
  31. package/.prettierignore +1 -0
  32. package/.prettierrc.json +9 -0
  33. package/CHANGELOG.md +25 -0
  34. package/CONTRIBUTING.md +31 -0
  35. package/LICENCE.md +674 -0
  36. package/README.md +273 -0
  37. package/bin/cli.js +5 -0
  38. package/bin/config.js +137 -0
  39. package/bin/vitePluginCompiiile/index.js +32 -0
  40. package/bin/vitePluginCompiiile/markdownConfig.js +30 -0
  41. package/bin/vitePluginCompiiile/models/Context.js +138 -0
  42. package/bin/vitePluginCompiiile/models/FileListItem.js +10 -0
  43. package/bin/vitePluginCompiiile/models/FilesTreeItem.js +8 -0
  44. package/bin/vitePluginCompiiile/models/RouteListItem.js +9 -0
  45. package/bin/vitePluginCompiiile/rehypeHandleYamlMatterPlugin.js +8 -0
  46. package/bin/vitePluginCompiiile/rehypeImagePlugin.js +51 -0
  47. package/bin/vitePluginCompiiile/rehypeLinkPlugin.js +20 -0
  48. package/build.js +16 -0
  49. package/compiiile.config.js +6 -0
  50. package/dist/style.css +1 -0
  51. package/markdown-preview.md +242 -0
  52. package/package.json +81 -0
  53. package/slides-preview.mdx +39 -0
  54. package/src/env.d.ts +1 -0
  55. package/tsconfig.json +6 -0
@@ -0,0 +1,48 @@
1
+ <template>
2
+ <nav class="no-print">
3
+ <files-tree :current-path="currentPath" />
4
+ </nav>
5
+ </template>
6
+
7
+ <script>
8
+ import FilesTree from "./FilesTree.vue"
9
+
10
+ export default {
11
+ name: "NavBar",
12
+ components: { FilesTree },
13
+ props: {
14
+ currentPath: {
15
+ type: String,
16
+ required: true
17
+ }
18
+ }
19
+ }
20
+ </script>
21
+
22
+ <style scoped lang="scss">
23
+ nav {
24
+ width: var(--nav-bar-width);
25
+ background-color: var(--darker-background-color);
26
+ padding: 30px 8px 30px var(--layout-padding);
27
+ flex: 0 0 auto;
28
+ position: fixed;
29
+ top: calc(var(--top-bar-height) + 1px);
30
+ left: 0;
31
+ height: calc(100vh - var(--top-bar-height) + 1px);
32
+ overflow: auto;
33
+ z-index: 1;
34
+ transition:
35
+ width 0.3s var(--ease-in-out-quart),
36
+ transform 0.1s ease;
37
+
38
+ @media screen and (max-width: 900px) {
39
+ width: 0;
40
+ transform: translateX(-100%);
41
+
42
+ &.navbar--opened {
43
+ width: 100vw;
44
+ transform: translateX(0);
45
+ }
46
+ }
47
+ }
48
+ </style>
@@ -0,0 +1,216 @@
1
+ <template>
2
+ <li class="nav-list-item no-wrap">
3
+ <template v-if="item.isDirectory">
4
+ <svg
5
+ class="directory-icon"
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width="15"
8
+ height="15"
9
+ fill="none"
10
+ viewBox="0 0 256 256"
11
+ >
12
+ <path
13
+ d="M216.9,208H39.4a7.4,7.4,0,0,1-7.4-7.4V80H216a8,8,0,0,1,8,8V200.9A7.1,7.1,0,0,1,216.9,208Z"
14
+ stroke-linecap="round"
15
+ stroke-linejoin="round"
16
+ stroke-width="16"
17
+ ></path>
18
+ <path
19
+ d="M32,80V56a8,8,0,0,1,8-8H92.7a7.9,7.9,0,0,1,5.6,2.3L128,80"
20
+ stroke-linecap="round"
21
+ stroke-linejoin="round"
22
+ stroke-width="16"
23
+ ></path>
24
+ </svg>
25
+
26
+ <span class="directory-name">{{ item.name }}</span>
27
+ <ul v-if="item.children.length > 0" class="nav-list-item-children">
28
+ <nav-list-item
29
+ v-for="child in item.children"
30
+ :key="child.uuid"
31
+ :item="child"
32
+ :current-path="currentPath"
33
+ />
34
+ </ul>
35
+ </template>
36
+
37
+ <template v-else>
38
+ <a :href="route.path" class="link" :class="[{ 'link-active': route.path === currentPath }]">
39
+ <svg
40
+ v-if="!route.meta.asSlides"
41
+ class="file-icon"
42
+ xmlns="http://www.w3.org/2000/svg"
43
+ width="13"
44
+ height="13"
45
+ fill="none"
46
+ viewBox="0 0 256 256"
47
+ >
48
+ <path
49
+ d="M200,224H56a8,8,0,0,1-8-8V40a8,8,0,0,1,8-8h96l56,56V216A8,8,0,0,1,200,224Z"
50
+ fill="none"
51
+ stroke-linecap="round"
52
+ stroke-linejoin="round"
53
+ stroke-width="16"
54
+ ></path>
55
+ <polyline
56
+ points="152 32 152 88 208 88"
57
+ fill="none"
58
+ stroke-linecap="round"
59
+ stroke-linejoin="round"
60
+ stroke-width="16"
61
+ ></polyline>
62
+ </svg>
63
+
64
+ <svg
65
+ v-else
66
+ class="file-icon"
67
+ xmlns="http://www.w3.org/2000/svg"
68
+ width="13"
69
+ height="13"
70
+ fill="none"
71
+ viewBox="0 0 256 256"
72
+ >
73
+ <rect width="256" height="256" fill="none"></rect>
74
+ <line
75
+ x1="48"
76
+ y1="184"
77
+ x2="48"
78
+ y2="72"
79
+ fill="none"
80
+ stroke-linecap="round"
81
+ stroke-linejoin="round"
82
+ stroke-width="16"
83
+ ></line>
84
+ <line
85
+ x1="208"
86
+ y1="72"
87
+ x2="208"
88
+ y2="184"
89
+ fill="none"
90
+ stroke-linecap="round"
91
+ stroke-linejoin="round"
92
+ stroke-width="16"
93
+ ></line>
94
+ <rect
95
+ x="32"
96
+ y="40"
97
+ width="192"
98
+ height="32"
99
+ rx="8"
100
+ fill="none"
101
+ stroke-linecap="round"
102
+ stroke-linejoin="round"
103
+ stroke-width="16"
104
+ ></rect>
105
+ <line
106
+ x1="128"
107
+ y1="184"
108
+ x2="128"
109
+ y2="216"
110
+ fill="none"
111
+ stroke-linecap="round"
112
+ stroke-linejoin="round"
113
+ stroke-width="16"
114
+ ></line>
115
+ <circle
116
+ cx="128"
117
+ cy="232"
118
+ r="16"
119
+ fill="none"
120
+ stroke-linecap="round"
121
+ stroke-linejoin="round"
122
+ stroke-width="16"
123
+ ></circle>
124
+ <line
125
+ x1="32"
126
+ y1="184"
127
+ x2="224"
128
+ y2="184"
129
+ fill="none"
130
+ stroke-linecap="round"
131
+ stroke-linejoin="round"
132
+ stroke-width="16"
133
+ ></line>
134
+ </svg>
135
+
136
+ <span class="link-name">{{ route.meta?.title || item.name }}</span>
137
+ </a>
138
+ </template>
139
+ </li>
140
+ </template>
141
+
142
+ <script>
143
+ export default {
144
+ name: "NavListItem",
145
+ props: {
146
+ item: {
147
+ type: Object,
148
+ required: true
149
+ },
150
+ currentPath: {
151
+ type: String,
152
+ required: true
153
+ }
154
+ },
155
+ computed: {
156
+ route() {
157
+ return this.$context.routeList.find((route) => route.name === this.item.uuid)
158
+ }
159
+ }
160
+ }
161
+ </script>
162
+
163
+ <style scoped lang="scss">
164
+ .nav-list-item-children {
165
+ list-style-type: none;
166
+ padding-left: 20px;
167
+ margin-top: 3px;
168
+ }
169
+
170
+ .nav-list-item {
171
+ padding: 5px 0;
172
+ color: var(--dimmed-text-color);
173
+ line-height: 1rem;
174
+ }
175
+
176
+ .directory-icon {
177
+ margin-left: 2px;
178
+ }
179
+
180
+ .directory-icon path {
181
+ stroke: var(--dimmed-text-color);
182
+ fill: var(--dimmed-text-color);
183
+ display: inline-block;
184
+ }
185
+
186
+ .directory-name {
187
+ display: inline;
188
+ margin-left: 3px;
189
+ position: relative;
190
+ top: -2px;
191
+ }
192
+
193
+ .file-icon {
194
+ stroke: var(--dimmed-text-color);
195
+ }
196
+
197
+ .link-name {
198
+ position: relative;
199
+ top: -2px;
200
+ margin-left: 2px;
201
+ }
202
+
203
+ .link {
204
+ text-decoration: none;
205
+ color: inherit;
206
+ }
207
+
208
+ .link-active {
209
+ font-weight: bold;
210
+ color: var(--text-color-base);
211
+
212
+ path {
213
+ stroke: var(--text-color-base);
214
+ }
215
+ }
216
+ </style>
@@ -0,0 +1,371 @@
1
+ <template>
2
+ <button class="fake-input" @click="openSearchModal">
3
+ <svg
4
+ class="ph-icon search-icon"
5
+ xmlns="http://www.w3.org/2000/svg"
6
+ width="192"
7
+ height="192"
8
+ fill="#000000"
9
+ viewBox="0 0 256 256"
10
+ >
11
+ <rect width="256" height="256" fill="none"></rect>
12
+ <circle
13
+ cx="116"
14
+ cy="116"
15
+ r="84"
16
+ fill="none"
17
+ stroke="#000000"
18
+ stroke-linecap="round"
19
+ stroke-linejoin="round"
20
+ stroke-width="16"
21
+ ></circle>
22
+ <line
23
+ x1="175.4"
24
+ y1="175.4"
25
+ x2="224"
26
+ y2="224"
27
+ fill="none"
28
+ stroke="#000000"
29
+ stroke-linecap="round"
30
+ stroke-linejoin="round"
31
+ stroke-width="16"
32
+ ></line>
33
+ </svg>
34
+ <span class="search-shortcut">
35
+ <svg
36
+ class="command-icon ph-icon"
37
+ xmlns="http://www.w3.org/2000/svg"
38
+ width="192"
39
+ height="192"
40
+ fill="#000000"
41
+ viewBox="0 0 256 256"
42
+ >
43
+ <rect width="256" height="256" fill="none"></rect>
44
+ <path
45
+ d="M180,48h0a28,28,0,0,1,28,28v0a28,28,0,0,1-28,28H152a0,0,0,0,1,0,0V76a28,28,0,0,1,28-28Z"
46
+ fill="none"
47
+ stroke="#000000"
48
+ stroke-linecap="round"
49
+ stroke-linejoin="round"
50
+ stroke-width="16"
51
+ ></path>
52
+ <path
53
+ d="M48,48H76a28,28,0,0,1,28,28v0a28,28,0,0,1-28,28h0A28,28,0,0,1,48,76V48A0,0,0,0,1,48,48Z"
54
+ transform="translate(152 152) rotate(180)"
55
+ fill="none"
56
+ stroke="#000000"
57
+ stroke-linecap="round"
58
+ stroke-linejoin="round"
59
+ stroke-width="16"
60
+ ></path>
61
+ <path
62
+ d="M152,152h28a28,28,0,0,1,28,28v0a28,28,0,0,1-28,28h0a28,28,0,0,1-28-28V152A0,0,0,0,1,152,152Z"
63
+ fill="none"
64
+ stroke="#000000"
65
+ stroke-linecap="round"
66
+ stroke-linejoin="round"
67
+ stroke-width="16"
68
+ ></path>
69
+ <path
70
+ d="M76,152h0a28,28,0,0,1,28,28v0a28,28,0,0,1-28,28H48a0,0,0,0,1,0,0V180A28,28,0,0,1,76,152Z"
71
+ transform="translate(152 360) rotate(-180)"
72
+ fill="none"
73
+ stroke="#000000"
74
+ stroke-linecap="round"
75
+ stroke-linejoin="round"
76
+ stroke-width="16"
77
+ ></path>
78
+ <rect
79
+ x="104"
80
+ y="104"
81
+ width="48"
82
+ height="48"
83
+ fill="none"
84
+ stroke="#000000"
85
+ stroke-linecap="round"
86
+ stroke-linejoin="round"
87
+ stroke-width="16"
88
+ ></rect></svg
89
+ >k
90
+ </span>
91
+ </button>
92
+
93
+ <div v-if="searchModalOpened" class="search-bar-wrapper">
94
+ <div class="search-overlay" @click="searchModalOpened = false"></div>
95
+
96
+ <div class="search-bar">
97
+ <div class="search-input-wrapper">
98
+ <label for="search-input" class="search-label">
99
+ <svg
100
+ class="ph-icon search-icon"
101
+ xmlns="http://www.w3.org/2000/svg"
102
+ width="192"
103
+ height="192"
104
+ fill="#000000"
105
+ viewBox="0 0 256 256"
106
+ >
107
+ <rect width="256" height="256" fill="none"></rect>
108
+ <circle
109
+ cx="116"
110
+ cy="116"
111
+ r="84"
112
+ fill="none"
113
+ stroke="#000000"
114
+ stroke-linecap="round"
115
+ stroke-linejoin="round"
116
+ stroke-width="16"
117
+ ></circle>
118
+ <line
119
+ x1="175.4"
120
+ y1="175.4"
121
+ x2="224"
122
+ y2="224"
123
+ fill="none"
124
+ stroke="#000000"
125
+ stroke-linecap="round"
126
+ stroke-linejoin="round"
127
+ stroke-width="16"
128
+ ></line>
129
+ </svg>
130
+ </label>
131
+ <input
132
+ id="search-input"
133
+ v-model="searchValue"
134
+ class="search-input"
135
+ @input="search"
136
+ @keyup.down="focusFirstSearchResult"
137
+ @keyup.up="focusLastSearchResult"
138
+ @keyup.esc="searchModalOpened = false"
139
+ />
140
+ </div>
141
+
142
+ <ul class="search-results">
143
+ <search-result
144
+ v-for="searchResult in searchResults"
145
+ :key="searchResult.fullPath"
146
+ :search-result="searchResult"
147
+ @keyup.down.prevent="onSearchResultDownKeyPress"
148
+ @keyup.up.prevent="onSearchResultUpKeyPress"
149
+ />
150
+ </ul>
151
+ </div>
152
+ </div>
153
+ </template>
154
+
155
+ <script>
156
+ import SearchResult from "./SearchResult.vue"
157
+ import { searchIndex } from "../../utils/searchIndex"
158
+
159
+ const RESULT_PREVIEW_CHARACTER_OFFSET = 120
160
+
161
+ export default {
162
+ name: "SearchBar",
163
+ components: { SearchResult },
164
+ data() {
165
+ return {
166
+ searchValue: "",
167
+ searchResults: [],
168
+ searchModalOpened: false
169
+ }
170
+ },
171
+ mounted() {
172
+ document.onkeydown = (e) => {
173
+ const key = e.which || e.keyCode
174
+
175
+ if ((e.ctrlKey || e.metaKey) && key === 75) {
176
+ this.openSearchModal()
177
+ }
178
+ }
179
+ },
180
+ methods: {
181
+ search() {
182
+ if (this.searchValue.trim().length > 1) {
183
+ const results = searchIndex.find(this.searchValue.trim())
184
+
185
+ const formattedResults = {}
186
+
187
+ for (const result of results) {
188
+ const uuid = result.item.uuid
189
+
190
+ if (!formattedResults[uuid]) {
191
+ const file = this.$context.fileList.find((file) => file.uuid === uuid)
192
+ formattedResults[uuid] = {
193
+ ...file,
194
+ contentMatches: []
195
+ }
196
+ }
197
+
198
+ let { textContent } = formattedResults[uuid]
199
+
200
+ const matchEndIndex = result.item.startIndex + result.end
201
+
202
+ let contentSlice = textContent.slice(
203
+ Math.max(result.item.startIndex + result.start - RESULT_PREVIEW_CHARACTER_OFFSET, 0),
204
+ result.item.startIndex + result.start
205
+ )
206
+
207
+ contentSlice += `<mark>`
208
+
209
+ contentSlice += textContent.slice(result.item.startIndex + result.start, matchEndIndex)
210
+
211
+ contentSlice += `</mark>`
212
+
213
+ contentSlice += textContent.slice(
214
+ matchEndIndex,
215
+ Math.min(textContent.length, matchEndIndex + RESULT_PREVIEW_CHARACTER_OFFSET)
216
+ )
217
+
218
+ formattedResults[uuid].contentMatches.push(contentSlice)
219
+ }
220
+
221
+ this.searchResults = Object.values(formattedResults)
222
+ } else {
223
+ this.searchResults = []
224
+ }
225
+ },
226
+ async openSearchModal() {
227
+ this.searchValue = ""
228
+ this.searchResults = []
229
+
230
+ this.searchModalOpened = true
231
+
232
+ await this.$nextTick()
233
+
234
+ const searchInput = document.querySelector("#search-input")
235
+ searchInput.focus()
236
+ },
237
+ focusFirstSearchResult() {
238
+ const firstSearchResult = document.querySelector(".search-results .search-result")
239
+ firstSearchResult.focus()
240
+ },
241
+ focusLastSearchResult() {
242
+ const lastSearchResult = document.querySelector(".search-results .search-result:last-child")
243
+ lastSearchResult.focus()
244
+ },
245
+ onSearchResultDownKeyPress(e) {
246
+ let nextSearchResult = e.target.nextElementSibling
247
+ if (nextSearchResult) {
248
+ nextSearchResult.focus()
249
+ } else {
250
+ this.focusFirstSearchResult()
251
+ }
252
+ },
253
+ onSearchResultUpKeyPress(e) {
254
+ let nextSearchResult = e.target.previousElementSibling
255
+ if (nextSearchResult) {
256
+ nextSearchResult.focus()
257
+ } else {
258
+ this.focusLastSearchResult()
259
+ }
260
+ }
261
+ }
262
+ }
263
+ </script>
264
+
265
+ <style scoped lang="scss">
266
+ .search-bar-wrapper {
267
+ position: fixed;
268
+ top: 0;
269
+ left: 0;
270
+ width: 100vw;
271
+ height: 100vh;
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ }
276
+
277
+ .search-overlay {
278
+ background-color: rgba(0, 0, 0, 0.3);
279
+ width: 100vw;
280
+ height: 100vh;
281
+ position: fixed;
282
+ top: 0;
283
+ left: 0;
284
+ }
285
+
286
+ .search-label {
287
+ position: absolute;
288
+ left: 10px;
289
+ top: 10px;
290
+ }
291
+
292
+ .search-bar {
293
+ position: relative;
294
+ width: min(95%, 600px);
295
+ padding: 10px;
296
+ background-color: var(--search-background-color);
297
+ border-radius: 4px;
298
+
299
+ --shadow-color: 255deg 11% 7%;
300
+ box-shadow:
301
+ 0px 0.2px 0.3px hsl(var(--shadow-color) / 0.05),
302
+ 0px 8.3px 11.9px -0.2px hsl(var(--shadow-color) / 0.22),
303
+ 0px 27.5px 39.4px -0.4px hsl(var(--shadow-color) / 0.38);
304
+ }
305
+
306
+ .search-input-wrapper {
307
+ position: relative;
308
+ }
309
+
310
+ .fake-input {
311
+ width: 100px;
312
+ border: solid 1px var(--search-input-border-color);
313
+ border-radius: 8px;
314
+ background-color: var(--darker-background-color);
315
+ height: 35px;
316
+ cursor: pointer;
317
+ display: flex;
318
+ justify-content: space-between;
319
+ align-items: center;
320
+ padding: 0 10px;
321
+ margin-left: auto;
322
+ flex: 0 0 auto;
323
+ }
324
+
325
+ .search-icon {
326
+ color: var(--dimmed-text-color);
327
+ width: 18px;
328
+ height: 18px;
329
+ }
330
+
331
+ .search-input {
332
+ width: 100%;
333
+ box-sizing: border-box;
334
+ height: 40px;
335
+ border-radius: 8px;
336
+ background-color: var(--darker-background-color);
337
+ padding: 10px 20px 10px 40px;
338
+ font-size: var(--text-md);
339
+ color: var(--text-color-light);
340
+ border: none;
341
+ display: block;
342
+ outline: none;
343
+
344
+ &:focus {
345
+ box-shadow: inset 0 0 2px 2px rgb(153 133 254 / 80%);
346
+ }
347
+ }
348
+
349
+ .search-results {
350
+ padding: 0;
351
+ margin: 10px 0 0;
352
+ list-style-type: none;
353
+ box-sizing: border-box;
354
+ height: min(60vh, 500px);
355
+ overflow: auto;
356
+ }
357
+
358
+ .search-shortcut {
359
+ color: var(--dimmed-text-color);
360
+ font-size: var(--text-sm);
361
+ display: flex;
362
+ align-items: center;
363
+ border: solid 1px var(--dimmed-text-color);
364
+ border-radius: 4px;
365
+ padding: 0 4px;
366
+ }
367
+
368
+ .command-icon {
369
+ margin-right: 3px;
370
+ }
371
+ </style>