@compiiile/compiiile 2.16.0 → 2.17.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/.compiiile/src/layouts/BaseLayout.astro +26 -0
- package/.compiiile/src/style/index.css +1 -1
- package/.compiiile/src/style/slides.css +2 -2
- package/.compiiile/src/style/texts.css +5 -1
- package/.compiiile/src/style/variables.css +2 -0
- package/4-pro-features.mdx +45 -1
- package/README.md +2 -1
- package/bin/config.js +4 -141
- package/bin/loadConfig.js +175 -0
- package/bin/vitePluginCompiiile/index.js +102 -1
- package/bin/vitePluginCompiiile/models/Context.js +23 -17
- package/package.json +2 -2
- package/.compiiile/components.d.ts +0 -23
- package/bin/.compiiile/src/env.d.ts +0 -1
|
@@ -40,5 +40,31 @@ const defaultTheme = site.theme
|
|
|
40
40
|
</head>
|
|
41
41
|
<body>
|
|
42
42
|
<slot></slot>
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
<script>
|
|
46
|
+
/*
|
|
47
|
+
Using HMR, we send a custom event when the `asSlides` frontmatter parameter changed.
|
|
48
|
+
The event contains the old and new route path based on whether the page needs to display slides.
|
|
49
|
+
We store the new page URL to redirect to in the sessionStorage because it follows this flow:
|
|
50
|
+
- the `switch-page-render` event is sent
|
|
51
|
+
- we receive it just below, and check if we are on the updated file's URL : we store the new URL to redirect to
|
|
52
|
+
- the whole page reloads because Compiiile vite's module in invalidated to reload its config and all files
|
|
53
|
+
- only when the reload is done, we get to the second `if`, where we change the current route URL
|
|
54
|
+
- the redirect is not made before the vite's module invalidation because the reload prevents the redirection from happening
|
|
55
|
+
*/
|
|
56
|
+
if (import.meta.hot) {
|
|
57
|
+
import.meta.hot.on('switch-page-render', (data) => {
|
|
58
|
+
if(window.location.pathname === data.oldRoutePath){
|
|
59
|
+
sessionStorage.setItem("COMPIIILE_SWITCH_PAGE_RENDER", window.location.origin + data.newRoutePath)
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if(sessionStorage.getItem("COMPIIILE_SWITCH_PAGE_RENDER")){
|
|
65
|
+
window.location.href = sessionStorage.getItem("COMPIIILE_SWITCH_PAGE_RENDER")
|
|
66
|
+
sessionStorage.removeItem("COMPIIILE_SWITCH_PAGE_RENDER")
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
43
69
|
</body>
|
|
44
70
|
</html>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
.reveal {
|
|
10
10
|
height: 100vh;
|
|
11
11
|
width: 100vw;
|
|
12
|
-
font-family:
|
|
12
|
+
font-family: var(--default-font) !important;
|
|
13
13
|
|
|
14
14
|
.slides {
|
|
15
15
|
text-align: inherit;
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
h4,
|
|
40
40
|
h5,
|
|
41
41
|
h6 {
|
|
42
|
-
font-family:
|
|
42
|
+
font-family: var(--heading-font);
|
|
43
43
|
font-variation-settings:
|
|
44
44
|
"wght" 900,
|
|
45
45
|
"wdth" 125;
|
|
@@ -3,7 +3,7 @@ h2,
|
|
|
3
3
|
h3,
|
|
4
4
|
h4,
|
|
5
5
|
h5 {
|
|
6
|
-
font-family:
|
|
6
|
+
font-family: var(--heading-font);
|
|
7
7
|
margin: 3rem 0 1.38rem;
|
|
8
8
|
line-height: 1;
|
|
9
9
|
font-variation-settings: "wght" 900;
|
|
@@ -87,3 +87,7 @@ body {
|
|
|
87
87
|
.hidden {
|
|
88
88
|
visibility: hidden;
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
details summary {
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
--ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
|
|
9
9
|
--monospace: "JetBrains Mono Variable", monospace;
|
|
10
10
|
--r-code-font: "JetBrains Mono Variable", monospace;
|
|
11
|
+
--heading-font: "Archivo Variable", sans-serif;
|
|
12
|
+
--default-font: "DM Sans Variable", sans-serif;
|
|
11
13
|
|
|
12
14
|
/* Dark theme by default */
|
|
13
15
|
--layout-background-color: #1b1b1f;
|
package/4-pro-features.mdx
CHANGED
|
@@ -5,6 +5,30 @@ description: "Use icons, admonitions, mermaid diagrams, markmap mindmaps in Mark
|
|
|
5
5
|
|
|
6
6
|
# compiiile-pro added features <Icon name="star" />
|
|
7
7
|
|
|
8
|
+
## Customize style by providing your own CSS file
|
|
9
|
+
|
|
10
|
+
You can customize every bit of the UI with your own style by passing a `css` param with the relative path to your css file :
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
compiiile-pro dev --css="./custom.css"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Here is an example of a CSS file content to set some colors and the default font:
|
|
17
|
+
|
|
18
|
+
```css
|
|
19
|
+
@import url(https://fonts.bunny.net/css?family=inter:200i,400,400i,900);
|
|
20
|
+
|
|
21
|
+
:root {
|
|
22
|
+
--layout-background-color: #0000ff;
|
|
23
|
+
--darker-background-color: #00ff00;
|
|
24
|
+
--default-font: "Inter", sans-serif;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
:nail_care: The list of global CSS variables can be found here : https://github.com/compiiile/compiiile/blob/master/.compiiile/src/style/variables.css
|
|
29
|
+
|
|
30
|
+
:rainbow: You can also just target CSS classes and tweak them the way you want.
|
|
31
|
+
|
|
8
32
|
## Admonitions
|
|
9
33
|
|
|
10
34
|
> [!NOTE]
|
|
@@ -572,7 +596,7 @@ The `CCard` component can be used as a traditional card or a link.
|
|
|
572
596
|
<details>
|
|
573
597
|
<summary>Source</summary>
|
|
574
598
|
|
|
575
|
-
````
|
|
599
|
+
````mdx
|
|
576
600
|
<CGrid gap="20px" template="1 1">
|
|
577
601
|
<CCard hintText="Go to the specific page">
|
|
578
602
|
[Check compiiile-pro installation](./3-pro-installation.md)
|
|
@@ -590,3 +614,23 @@ The `CCard` component can be used as a traditional card or a link.
|
|
|
590
614
|
````
|
|
591
615
|
|
|
592
616
|
</details>
|
|
617
|
+
|
|
618
|
+
### CDetails
|
|
619
|
+
|
|
620
|
+
The `CDetails` component allows you to hide a block and reveal it by clicking on an arrow, just like the `details` HTML tag.
|
|
621
|
+
|
|
622
|
+
- The title can be set via a `summary` prop or a `summary` slot
|
|
623
|
+
|
|
624
|
+
<CDetails summary="Example">
|
|
625
|
+
> [!TIP]
|
|
626
|
+
> This is lit! :sparkles:
|
|
627
|
+
</CDetails>
|
|
628
|
+
|
|
629
|
+
<CDetails summary="Source">
|
|
630
|
+
```mdx
|
|
631
|
+
<CDetails summary="Example">
|
|
632
|
+
> [!TIP]
|
|
633
|
+
> This is lit! :sparkles:
|
|
634
|
+
</CDetails>
|
|
635
|
+
```
|
|
636
|
+
</CDetails>
|
package/README.md
CHANGED
|
@@ -197,7 +197,7 @@ The home page of Compiiile (`/`) points to a `README.md` file located at the roo
|
|
|
197
197
|
Here is the list of parameters that you can set to customize Compiiile (none are required):
|
|
198
198
|
|
|
199
199
|
| Parameter | Type | Description |
|
|
200
|
-
|
|
200
|
+
| ---------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
201
201
|
| `title` | `string` | The title to display on the top-left of the User Interface |
|
|
202
202
|
| `description` | `string` | The description that is rendered by default for the SEO |
|
|
203
203
|
| `logo` | `string` | The relative path of the logo to display in the TopBar and as favicon |
|
|
@@ -212,6 +212,7 @@ Here is the list of parameters that you can set to customize Compiiile (none are
|
|
|
212
212
|
| `publicDir` | `string` | The folder name in which you can serve public files, defaults to `public` |
|
|
213
213
|
| `vite.server.fs.allow` | `string[]` | Add local paths to vite's server fs allow list |
|
|
214
214
|
| `printReady` | `Boolean` | Add a `/print` page to display a full ready-to-print content (uses `@compiiile/compiiile-print`) |
|
|
215
|
+
| `css` | `string` | A relative path to a custom CSS file to customize the style <br/>:warning: Requires `compiiile-pro` |
|
|
215
216
|
|
|
216
217
|
You can use these parameters in 2 ways:
|
|
217
218
|
|
package/bin/config.js
CHANGED
|
@@ -4,114 +4,17 @@ import { passthroughImageService } from "astro/config"
|
|
|
4
4
|
import compiiile from "./vitePluginCompiiile/index.js"
|
|
5
5
|
import mdx from "@astrojs/mdx"
|
|
6
6
|
import path from "node:path"
|
|
7
|
-
import { copyFileSync, cpSync, existsSync } from "node:fs"
|
|
8
7
|
import { fileURLToPath } from "node:url"
|
|
9
8
|
import markdownConfig from "./vitePluginCompiiile/markdownConfig.js"
|
|
10
9
|
import sitemap from "@astrojs/sitemap"
|
|
11
|
-
import { loadConfig } from "c12"
|
|
12
|
-
import yargs from "yargs/yargs"
|
|
13
|
-
import { hideBin } from "yargs/helpers"
|
|
14
10
|
|
|
15
|
-
import { readFile } from "node:fs/promises"
|
|
16
11
|
// Making sure fonts are accessible by vite's server
|
|
17
12
|
import { createRequire } from "node:module"
|
|
18
13
|
import { packageDirectory } from "pkg-dir"
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
process.env.COMPIIILE_SOURCE = source
|
|
15
|
+
import { loadConfig } from "./loadConfig.js"
|
|
22
16
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
/*
|
|
26
|
-
Order of options by priority:
|
|
27
|
-
1. command arguments
|
|
28
|
-
2. user-defined config in dedicated file
|
|
29
|
-
3. default config as fallback
|
|
30
|
-
*/
|
|
31
|
-
let configFromFile = {}
|
|
32
|
-
try {
|
|
33
|
-
configFromFile = (await loadConfig({ name: "compiiile" })).config
|
|
34
|
-
} catch {
|
|
35
|
-
// This means that no config file was provided: getting parameters from script parameters instead
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const argv = yargs(hideBin(process.argv))
|
|
39
|
-
.parserConfiguration({
|
|
40
|
-
"deep-merge-config": true
|
|
41
|
-
})
|
|
42
|
-
.alias("v", "version")
|
|
43
|
-
.config(configFromFile)
|
|
44
|
-
.command("dev", "launch development server")
|
|
45
|
-
.command("build", "build")
|
|
46
|
-
.command("preview", "preview")
|
|
47
|
-
.option("port", {
|
|
48
|
-
describe: "Port to use",
|
|
49
|
-
default: 4321
|
|
50
|
-
})
|
|
51
|
-
.option("host", {
|
|
52
|
-
describe: "Host to use",
|
|
53
|
-
default: "127.0.0.1"
|
|
54
|
-
})
|
|
55
|
-
.option("title", {
|
|
56
|
-
describe: "The title to display on the top-left of the User Interface"
|
|
57
|
-
})
|
|
58
|
-
.option("description", {
|
|
59
|
-
describe: "The description that is rendered by default for the SEO"
|
|
60
|
-
})
|
|
61
|
-
.option("logo", {
|
|
62
|
-
describe: "The relative path of the logo to display in the TopBar and as favicon"
|
|
63
|
-
})
|
|
64
|
-
.option("logoUrl", {
|
|
65
|
-
describe: "The url to go to when clicking on the logo, defaults to the home page if not set"
|
|
66
|
-
})
|
|
67
|
-
.option("dest", {
|
|
68
|
-
describe: "The folder in which to build files, defaults to `./.compiiile/dist`"
|
|
69
|
-
})
|
|
70
|
-
.option("siteUrl", {
|
|
71
|
-
describe: "The url of the website in production (without trailing slash), used for the SEO tag `og:image`"
|
|
72
|
-
})
|
|
73
|
-
.option("astroConfig", {
|
|
74
|
-
describe: "Override default Astro config (https://docs.astro.build/en/reference/configuration-reference/)"
|
|
75
|
-
})
|
|
76
|
-
.option("data", {
|
|
77
|
-
describe: "An object with data to use in MDX files"
|
|
78
|
-
})
|
|
79
|
-
.option("theme", {
|
|
80
|
-
describe:
|
|
81
|
-
"The website theme, value can be : `auto` (default value: adapts to system preferences) | `light` | `dark`"
|
|
82
|
-
})
|
|
83
|
-
.option("useAutoTitles", {
|
|
84
|
-
describe:
|
|
85
|
-
"If set to `true`, use the first file heading as title to be displayed in the navbar and for SEO. Defaults to `false`"
|
|
86
|
-
})
|
|
87
|
-
.option("noIndex", {
|
|
88
|
-
describe:
|
|
89
|
-
"If set to `true`, the `robots.txt` file will disallow all routes, preventing indexation. Defaults to `false`"
|
|
90
|
-
})
|
|
91
|
-
.option("publicDir", {
|
|
92
|
-
describe: "The folder name in which you can serve public files, defaults to `public`"
|
|
93
|
-
})
|
|
94
|
-
.option("vite.server.fs.allow", {
|
|
95
|
-
describe: "Add local paths to vite's server fs allow list"
|
|
96
|
-
})
|
|
97
|
-
.option("printReady", {
|
|
98
|
-
describe: "Add a /print page to display a full ready-to-print content (uses @compiiile/compiiile-print)"
|
|
99
|
-
})
|
|
100
|
-
.help()
|
|
101
|
-
.version(packageJSON.version).argv
|
|
102
|
-
|
|
103
|
-
process.env.VITE_COMPIIILE_SITE_URL = argv.siteUrl ?? ""
|
|
104
|
-
process.env.VITE_COMPIIILE_NO_INDEX = /true/i.test(argv.noIndex) // defaults to `false` if not set or not equal to `true`
|
|
105
|
-
|
|
106
|
-
process.env.VITE_COMPIIILE_TITLE = argv.title ?? ""
|
|
107
|
-
process.env.VITE_COMPIIILE_DESCRIPTION = argv.description ?? ""
|
|
108
|
-
|
|
109
|
-
process.env.VITE_COMPIIILE_LOGO_URL = argv.logoUrl ?? ""
|
|
110
|
-
|
|
111
|
-
process.env.VITE_COMPIIILE_THEME = argv.theme ?? "auto"
|
|
112
|
-
|
|
113
|
-
process.env.VITE_COMPIIILE_DATA = JSON.stringify(argv.data ?? {})
|
|
114
|
-
process.env.VITE_COMPIIILE_USE_AUTO_TITLES = /true/i.test(argv.useAutoTitles) // defaults to `false` if not set or not equal to `true`
|
|
17
|
+
const { argv, localIntegrations, configFromFile, source, hasPublicFiles, publicDir } = await loadConfig()
|
|
115
18
|
|
|
116
19
|
// Get command and set env
|
|
117
20
|
const IS_DEV = argv._.length === 0 || argv._.includes("dev")
|
|
@@ -126,35 +29,6 @@ if (IS_DEV) {
|
|
|
126
29
|
process.env.NODE_ENV = NODE_ENV_PRODUCTION
|
|
127
30
|
}
|
|
128
31
|
|
|
129
|
-
// Handling logo and favicon
|
|
130
|
-
process.env.VITE_COMPIIILE_LOGO = null
|
|
131
|
-
|
|
132
|
-
const publicDir = path.resolve(source, "./.compiiile/public")
|
|
133
|
-
|
|
134
|
-
const localPublicDirName = argv.publicDir ?? "public"
|
|
135
|
-
const localPublicDir = path.resolve(source, localPublicDirName)
|
|
136
|
-
const localPublicDirExists = existsSync(localPublicDir)
|
|
137
|
-
|
|
138
|
-
const hasPublicFiles = localPublicDirExists || argv.logo
|
|
139
|
-
if (hasPublicFiles) {
|
|
140
|
-
cpSync(fileURLToPath(new URL("../.compiiile/public", import.meta.url)), publicDir, { recursive: true })
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (localPublicDirExists) {
|
|
144
|
-
cpSync(localPublicDir, publicDir, { recursive: true })
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
if (argv.logo) {
|
|
148
|
-
try {
|
|
149
|
-
copyFileSync(path.resolve(source, argv.logo), path.resolve(publicDir, "favicon.png"))
|
|
150
|
-
// Set the logo to be displayed on the top bar if we were able to copy
|
|
151
|
-
process.env.VITE_COMPIIILE_LOGO = argv.logo
|
|
152
|
-
} catch (e) {
|
|
153
|
-
console.log(e)
|
|
154
|
-
console.error("Could not load provided logo: set a relative url from the current folder")
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
32
|
const require = createRequire(import.meta.url)
|
|
159
33
|
const pathName = require.resolve("@fontsource-variable/archivo")
|
|
160
34
|
|
|
@@ -164,13 +38,6 @@ if (packageDir) {
|
|
|
164
38
|
viteServerFsAllowList.push(packageDir)
|
|
165
39
|
}
|
|
166
40
|
|
|
167
|
-
const localIntegrations = []
|
|
168
|
-
|
|
169
|
-
if(/true/i.test(argv.printReady)){
|
|
170
|
-
const compiiilePrintIntegration = (await import("@compiiile/compiiile-print")).default
|
|
171
|
-
localIntegrations.push(compiiilePrintIntegration())
|
|
172
|
-
}
|
|
173
|
-
|
|
174
41
|
const astroConfig = {
|
|
175
42
|
server: {
|
|
176
43
|
host: argv.host,
|
|
@@ -241,12 +108,8 @@ const astroConfig = {
|
|
|
241
108
|
image: {
|
|
242
109
|
service: passthroughImageService()
|
|
243
110
|
},
|
|
244
|
-
...(configFromFile.astroConfig ?? {})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
process.env.VITE_COMPIIILE_BASE = astroConfig.base
|
|
248
|
-
if (process.env.VITE_COMPIIILE_BASE !== "/" && process.env.VITE_COMPIIILE_BASE.endsWith("/")) {
|
|
249
|
-
process.env.VITE_COMPIIILE_BASE = process.env.VITE_COMPIIILE_BASE.slice(0, -1)
|
|
111
|
+
...(configFromFile.astroConfig ?? {}),
|
|
112
|
+
...(argv.astroConfig ?? {})
|
|
250
113
|
}
|
|
251
114
|
|
|
252
115
|
const run = async (astroConfig) => {
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises"
|
|
2
|
+
import { fileURLToPath } from "node:url"
|
|
3
|
+
import yargs from "yargs/yargs"
|
|
4
|
+
import { hideBin } from "yargs/helpers"
|
|
5
|
+
import path from "node:path"
|
|
6
|
+
import { copyFileSync, cpSync, existsSync, rmSync } from "node:fs"
|
|
7
|
+
import { loadConfig as loadConfigFile } from "c12"
|
|
8
|
+
|
|
9
|
+
export const loadConfig = async () => {
|
|
10
|
+
const source = process.cwd()
|
|
11
|
+
process.env.COMPIIILE_SOURCE = source
|
|
12
|
+
|
|
13
|
+
const packageJSON = JSON.parse(await readFile(fileURLToPath(new URL("../package.json", import.meta.url))))
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
Order of options by priority:
|
|
17
|
+
1. command arguments
|
|
18
|
+
2. user-defined config in dedicated file
|
|
19
|
+
3. default config as fallback
|
|
20
|
+
*/
|
|
21
|
+
let configFromFile = {}
|
|
22
|
+
let compiiileConfig = {}
|
|
23
|
+
try {
|
|
24
|
+
compiiileConfig = await loadConfigFile({
|
|
25
|
+
name: process.env.COMPIIILE_TEMP_CONFIG_NAME || "compiiile",
|
|
26
|
+
cwd: process.env.COMPIIILE_TEMP_DIR || source
|
|
27
|
+
})
|
|
28
|
+
configFromFile = JSON.parse(JSON.stringify(compiiileConfig.config))
|
|
29
|
+
if (!process.env.COMPIIILE_CONFIG_FILE) {
|
|
30
|
+
process.env.COMPIIILE_CONFIG_FILE = compiiileConfig.configFile
|
|
31
|
+
}
|
|
32
|
+
} catch {
|
|
33
|
+
// This means that no config file was provided: getting parameters from script parameters instead
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (process.env.COMPIIILE_TEMP_DIR) {
|
|
37
|
+
rmSync(process.env.COMPIIILE_TEMP_DIR, { recursive: true, force: true })
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!configFromFile.astroConfig?.base) {
|
|
41
|
+
if (!configFromFile.astroConfig) {
|
|
42
|
+
configFromFile.astroConfig = {}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
configFromFile.astroConfig.base = "/"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const argv = yargs(hideBin(process.argv))
|
|
49
|
+
.parserConfiguration({
|
|
50
|
+
"deep-merge-config": true
|
|
51
|
+
})
|
|
52
|
+
.alias("v", "version")
|
|
53
|
+
.config(configFromFile)
|
|
54
|
+
.command("dev", "launch development server")
|
|
55
|
+
.command("build", "build")
|
|
56
|
+
.command("preview", "preview")
|
|
57
|
+
.option("port", {
|
|
58
|
+
describe: "Port to use",
|
|
59
|
+
default: 4321
|
|
60
|
+
})
|
|
61
|
+
.option("host", {
|
|
62
|
+
describe: "Host to use",
|
|
63
|
+
default: "127.0.0.1"
|
|
64
|
+
})
|
|
65
|
+
.option("title", {
|
|
66
|
+
describe: "The title to display on the top-left of the User Interface"
|
|
67
|
+
})
|
|
68
|
+
.option("description", {
|
|
69
|
+
describe: "The description that is rendered by default for the SEO"
|
|
70
|
+
})
|
|
71
|
+
.option("logo", {
|
|
72
|
+
describe: "The relative path of the logo to display in the TopBar and as favicon"
|
|
73
|
+
})
|
|
74
|
+
.option("logoUrl", {
|
|
75
|
+
describe: "The url to go to when clicking on the logo, defaults to the home page if not set"
|
|
76
|
+
})
|
|
77
|
+
.option("dest", {
|
|
78
|
+
describe: "The folder in which to build files, defaults to `./.compiiile/dist`"
|
|
79
|
+
})
|
|
80
|
+
.option("siteUrl", {
|
|
81
|
+
describe: "The url of the website in production (without trailing slash), used for the SEO tag `og:image`"
|
|
82
|
+
})
|
|
83
|
+
.option("astroConfig", {
|
|
84
|
+
describe: "Override default Astro config (https://docs.astro.build/en/reference/configuration-reference/)"
|
|
85
|
+
})
|
|
86
|
+
.option("data", {
|
|
87
|
+
describe: "An object with data to use in MDX files"
|
|
88
|
+
})
|
|
89
|
+
.option("theme", {
|
|
90
|
+
describe:
|
|
91
|
+
"The website theme, value can be : `auto` (default value: adapts to system preferences) | `light` | `dark`"
|
|
92
|
+
})
|
|
93
|
+
.option("useAutoTitles", {
|
|
94
|
+
describe:
|
|
95
|
+
"If set to `true`, use the first file heading as title to be displayed in the navbar and for SEO. Defaults to `false`"
|
|
96
|
+
})
|
|
97
|
+
.option("noIndex", {
|
|
98
|
+
describe:
|
|
99
|
+
"If set to `true`, the `robots.txt` file will disallow all routes, preventing indexation. Defaults to `false`"
|
|
100
|
+
})
|
|
101
|
+
.option("publicDir", {
|
|
102
|
+
describe: "The folder name in which you can serve public files, defaults to `public`"
|
|
103
|
+
})
|
|
104
|
+
.option("vite.server.fs.allow", {
|
|
105
|
+
describe: "Add local paths to vite's server fs allow list"
|
|
106
|
+
})
|
|
107
|
+
.option("printReady", {
|
|
108
|
+
describe: "Add a /print page to display a full ready-to-print content (uses @compiiile/compiiile-print)"
|
|
109
|
+
})
|
|
110
|
+
.help()
|
|
111
|
+
.version(packageJSON.version).argv
|
|
112
|
+
|
|
113
|
+
process.env.VITE_COMPIIILE_SITE_URL = argv.siteUrl ?? ""
|
|
114
|
+
process.env.VITE_COMPIIILE_NO_INDEX = /true/i.test(argv.noIndex) // defaults to `false` if not set or not equal to `true`
|
|
115
|
+
|
|
116
|
+
process.env.VITE_COMPIIILE_TITLE = argv.title ?? ""
|
|
117
|
+
process.env.VITE_COMPIIILE_DESCRIPTION = argv.description ?? ""
|
|
118
|
+
|
|
119
|
+
process.env.VITE_COMPIIILE_LOGO_URL = argv.logoUrl ?? ""
|
|
120
|
+
|
|
121
|
+
process.env.VITE_COMPIIILE_THEME = argv.theme ?? "auto"
|
|
122
|
+
|
|
123
|
+
process.env.VITE_COMPIIILE_DATA = typeof argv.data === "string" ? argv.data : JSON.stringify(argv.data ?? {})
|
|
124
|
+
process.env.VITE_COMPIIILE_USE_AUTO_TITLES = /true/i.test(argv.useAutoTitles) // defaults to `false` if not set or not equal to `true`
|
|
125
|
+
|
|
126
|
+
// Handling logo and favicon
|
|
127
|
+
process.env.VITE_COMPIIILE_LOGO = null
|
|
128
|
+
|
|
129
|
+
const publicDir = path.resolve(source, "./.compiiile/public")
|
|
130
|
+
|
|
131
|
+
const localPublicDirName = argv.publicDir ?? "public"
|
|
132
|
+
const localPublicDir = path.resolve(source, localPublicDirName)
|
|
133
|
+
const localPublicDirExists = existsSync(localPublicDir)
|
|
134
|
+
|
|
135
|
+
const hasPublicFiles = localPublicDirExists || argv.logo
|
|
136
|
+
if (hasPublicFiles) {
|
|
137
|
+
cpSync(fileURLToPath(new URL("../.compiiile/public", import.meta.url)), publicDir, { recursive: true })
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (localPublicDirExists) {
|
|
141
|
+
cpSync(localPublicDir, publicDir, { recursive: true })
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (argv.logo) {
|
|
145
|
+
try {
|
|
146
|
+
copyFileSync(path.resolve(source, argv.logo), path.resolve(publicDir, "favicon.png"))
|
|
147
|
+
// Set the logo to be displayed on the top bar if we were able to copy
|
|
148
|
+
process.env.VITE_COMPIIILE_LOGO = argv.logo
|
|
149
|
+
} catch (e) {
|
|
150
|
+
console.log(e)
|
|
151
|
+
console.error("Could not load provided logo: set a relative url from the current folder")
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const localIntegrations = []
|
|
156
|
+
|
|
157
|
+
if (/true/i.test(argv.printReady)) {
|
|
158
|
+
const compiiilePrintIntegration = (await import("@compiiile/compiiile-print")).default
|
|
159
|
+
localIntegrations.push(compiiilePrintIntegration())
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
process.env.VITE_COMPIIILE_BASE = argv.astroConfig.base
|
|
163
|
+
if (process.env.VITE_COMPIIILE_BASE !== "/" && process.env.VITE_COMPIIILE_BASE.endsWith("/")) {
|
|
164
|
+
process.env.VITE_COMPIIILE_BASE = process.env.VITE_COMPIIILE_BASE.slice(0, -1)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
argv,
|
|
169
|
+
localIntegrations,
|
|
170
|
+
configFromFile,
|
|
171
|
+
source,
|
|
172
|
+
hasPublicFiles,
|
|
173
|
+
publicDir
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import Context from "./models/Context.js"
|
|
2
|
+
import { createMarkdownProcessor } from "@astrojs/markdown-remark"
|
|
3
|
+
import markdownConfig from "./markdownConfig.js"
|
|
4
|
+
import path from "node:path"
|
|
5
|
+
import { loadConfig } from "../loadConfig.js"
|
|
6
|
+
import { promises as fs } from "node:fs"
|
|
2
7
|
|
|
3
8
|
const source = "."
|
|
4
9
|
|
|
10
|
+
let context = null
|
|
11
|
+
|
|
12
|
+
const pathFromSource = (filePath) => {
|
|
13
|
+
return filePath?.replace(process.env.COMPIIILE_SOURCE + "/", "")
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
export default function compiiile() {
|
|
6
17
|
const virtualModuleId = "virtual:compiiile"
|
|
7
18
|
const resolvedVirtualModuleId = "\0" + virtualModuleId
|
|
@@ -18,7 +29,7 @@ export default function compiiile() {
|
|
|
18
29
|
return
|
|
19
30
|
}
|
|
20
31
|
|
|
21
|
-
|
|
32
|
+
context = new Context()
|
|
22
33
|
context.filesTree = await context.scanDirectoryRecursively(source)
|
|
23
34
|
process.env.context = JSON.stringify(context)
|
|
24
35
|
|
|
@@ -27,6 +38,96 @@ export default function compiiile() {
|
|
|
27
38
|
const routeList = ${JSON.stringify(context.routeList)};\n\n
|
|
28
39
|
const site = ${JSON.stringify(context.site)};\n\n
|
|
29
40
|
export { fileList, filesTree, routeList, site };`
|
|
41
|
+
},
|
|
42
|
+
async hotUpdate({ file, read }) {
|
|
43
|
+
let shouldReloadPlugin = false
|
|
44
|
+
const absolutePath = pathFromSource(file)
|
|
45
|
+
|
|
46
|
+
if (file.match(/.*\.mdx?/)) {
|
|
47
|
+
try {
|
|
48
|
+
const content = await read()
|
|
49
|
+
|
|
50
|
+
const routeListItem = context.routeList.find((route) => route.fullPath === absolutePath)
|
|
51
|
+
|
|
52
|
+
const markdownProcessor = await createMarkdownProcessor(markdownConfig)
|
|
53
|
+
const renderedMarkdown = await markdownProcessor.render(content)
|
|
54
|
+
|
|
55
|
+
const title = context.getFileTitleFromProcessedMarkdown(renderedMarkdown)
|
|
56
|
+
const meta = renderedMarkdown.metadata.frontmatter
|
|
57
|
+
meta.title = title || path.parse(file).name
|
|
58
|
+
|
|
59
|
+
const fileMetaChanged = JSON.stringify(routeListItem?.meta || {}) !== JSON.stringify(meta)
|
|
60
|
+
|
|
61
|
+
shouldReloadPlugin = fileMetaChanged || !routeListItem
|
|
62
|
+
|
|
63
|
+
const prevStateWasAsSlides = !!routeListItem?.meta?.asSlides
|
|
64
|
+
const currentStateIsAsSlides = !!meta.asSlides
|
|
65
|
+
|
|
66
|
+
if (prevStateWasAsSlides !== currentStateIsAsSlides) {
|
|
67
|
+
const newRoutePath = context.generateRoutePathFromFilePath(
|
|
68
|
+
routeListItem.fullPath,
|
|
69
|
+
"",
|
|
70
|
+
currentStateIsAsSlides,
|
|
71
|
+
context.getEntryFileMatcher([routeListItem.fullPath])
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
this.environment.hot.send({
|
|
75
|
+
type: "custom",
|
|
76
|
+
event: "switch-page-render",
|
|
77
|
+
data: {
|
|
78
|
+
oldRoutePath: routeListItem.path,
|
|
79
|
+
newRoutePath: newRoutePath
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
} catch (e) {
|
|
84
|
+
if (e.code === "ENOENT") {
|
|
85
|
+
// The file has been deleted
|
|
86
|
+
shouldReloadPlugin = true
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const compiiileConfigFilePath = pathFromSource(process.env.COMPIIILE_CONFIG_FILE)
|
|
92
|
+
const compiiileConfigFileNewlyCreated =
|
|
93
|
+
absolutePath.match(/^compiiile\.config\.(m|c)?js$/) &&
|
|
94
|
+
process.env.COMPIIILE_CONFIG_FILE === "compiiile.config"
|
|
95
|
+
|
|
96
|
+
if (absolutePath === compiiileConfigFilePath || compiiileConfigFileNewlyCreated) {
|
|
97
|
+
shouldReloadPlugin = true
|
|
98
|
+
|
|
99
|
+
// WHY we do all this stuff and don't just import the config:
|
|
100
|
+
// "the file change callback may fire too fast before the editor finishes updating the file"
|
|
101
|
+
// https://vite.dev/guide/api-plugin.html#handlehotupdate
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const compiiileConfigFileContent = await read()
|
|
105
|
+
const tempConfigName = `${Date.now()}-temp-compiiile`
|
|
106
|
+
const tempDir = path.join(process.env.COMPIIILE_SOURCE, ".compiiile", ".temp")
|
|
107
|
+
await fs.mkdir(tempDir, { recursive: true }).catch(console.error)
|
|
108
|
+
const filePath = path.join(tempDir, tempConfigName + ".config.mjs")
|
|
109
|
+
await fs.writeFile(filePath, compiiileConfigFileContent)
|
|
110
|
+
process.env.COMPIIILE_TEMP_DIR = tempDir
|
|
111
|
+
process.env.COMPIIILE_TEMP_CONFIG_NAME = tempConfigName
|
|
112
|
+
} catch (e) {
|
|
113
|
+
// Config file has been deleted
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Whether the config file has been created / updated / deleted, we reload the whole config with args + env parameters
|
|
117
|
+
await loadConfig()
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (shouldReloadPlugin) {
|
|
121
|
+
// Invalidate the plugin module so it gets re-imported
|
|
122
|
+
const pluginModule = this.environment.moduleGraph.getModuleById(resolvedVirtualModuleId)
|
|
123
|
+
if (pluginModule) {
|
|
124
|
+
this.environment.moduleGraph.invalidateModule(pluginModule)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
this.environment.hot.send({ type: "full-reload" })
|
|
128
|
+
|
|
129
|
+
return []
|
|
130
|
+
}
|
|
30
131
|
}
|
|
31
132
|
}
|
|
32
133
|
}
|
|
@@ -55,6 +55,25 @@ export default class {
|
|
|
55
55
|
}/${asSlides ? this.SLIDES_BASE_PATH : this.WORKSPACE_BASE_PATH}/${sluggifiedPath}${hash}`
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
getFileTitleFromProcessedMarkdown(processedMarkdown) {
|
|
59
|
+
let firstHeading = null
|
|
60
|
+
if (JSON.parse(process.env.VITE_COMPIIILE_USE_AUTO_TITLES) && processedMarkdown.metadata.headings.length > 0) {
|
|
61
|
+
let firstHeadingIndex = 0
|
|
62
|
+
if (Object.keys(processedMarkdown.metadata.frontmatter).length > 0) {
|
|
63
|
+
// If a frontmatter is set, it is present as the first index in the `headings` array
|
|
64
|
+
firstHeadingIndex = 1
|
|
65
|
+
}
|
|
66
|
+
// Remove the starting '#' from the title
|
|
67
|
+
firstHeading = processedMarkdown.metadata.headings[firstHeadingIndex]?.text?.slice(1)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return processedMarkdown.metadata.frontmatter.title || firstHeading
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getEntryFileMatcher(files) {
|
|
74
|
+
return files.find((file) => file.toLowerCase().match(/^readme.mdx?$/)) ? /readme/ : /index/
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
async scanDirectoryRecursively(directoryPath) {
|
|
59
78
|
const fileArray = []
|
|
60
79
|
|
|
@@ -65,7 +84,7 @@ export default class {
|
|
|
65
84
|
|
|
66
85
|
const files = fs.readdirSync(directoryPath).sort(collator.compare)
|
|
67
86
|
|
|
68
|
-
const entryFileMatcher =
|
|
87
|
+
const entryFileMatcher = this.getEntryFileMatcher(files)
|
|
69
88
|
|
|
70
89
|
for (let file of files) {
|
|
71
90
|
if (
|
|
@@ -153,23 +172,10 @@ export default class {
|
|
|
153
172
|
continue
|
|
154
173
|
}
|
|
155
174
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
JSON.parse(process.env.VITE_COMPIIILE_USE_AUTO_TITLES) &&
|
|
159
|
-
renderedMarkdown.metadata.headings.length > 0
|
|
160
|
-
) {
|
|
161
|
-
let firstHeadingIndex = 0
|
|
162
|
-
if (Object.keys(renderedMarkdown.metadata.frontmatter).length > 0) {
|
|
163
|
-
// If a frontmatter is set, it is present as the first index in the `headings` array
|
|
164
|
-
firstHeadingIndex = 1
|
|
165
|
-
}
|
|
166
|
-
// Remove the starting '#' from the title
|
|
167
|
-
firstHeading = renderedMarkdown.metadata.headings[firstHeadingIndex]?.text?.slice(1)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
fileListItem.title = meta.title || firstHeading || fileName
|
|
175
|
+
const title = this.getFileTitleFromProcessedMarkdown(renderedMarkdown) || fileName
|
|
176
|
+
fileListItem.title = title
|
|
171
177
|
fileListItem.meta = meta
|
|
172
|
-
fileListItem.meta.title =
|
|
178
|
+
fileListItem.meta.title = title
|
|
173
179
|
fileListItem.fullPath = filePath
|
|
174
180
|
|
|
175
181
|
const routePath = this.generateRoutePathFromFilePath(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compiiile/compiiile",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.17.0",
|
|
5
5
|
"description": "The most convenient way to render a folder containing markdown files. Previewing and searching markdown files has never been that easy.",
|
|
6
6
|
"author": "AlbanCrepel <alban.crepel@gmail.com>",
|
|
7
7
|
"license": "GPL-3.0-only",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@babel/eslint-parser": "^7.25.9",
|
|
30
30
|
"@babel/parser": "^7.26.3",
|
|
31
31
|
"@compiiile/compiiile-print": "^1.0.6",
|
|
32
|
-
"@compiiile/compiiile-pro": "^1.
|
|
32
|
+
"@compiiile/compiiile-pro": "^1.2.0",
|
|
33
33
|
"@eslint/compat": "^1.2.4",
|
|
34
34
|
"@eslint/js": "^9.16.0",
|
|
35
35
|
"@fontsource-variable/archivo": "^5.1.0",
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
// @ts-nocheck
|
|
3
|
-
// Generated by unplugin-vue-components
|
|
4
|
-
// Read more: https://github.com/vuejs/core/pull/3399
|
|
5
|
-
export {}
|
|
6
|
-
|
|
7
|
-
/* prettier-ignore */
|
|
8
|
-
declare module 'vue' {
|
|
9
|
-
export interface GlobalComponents {
|
|
10
|
-
ClientScript: typeof import('./src/components/ClientScript.vue')['default']
|
|
11
|
-
ContentWrapper: typeof import('./src/components/ContentWrapper.vue')['default']
|
|
12
|
-
FilesTree: typeof import('./src/components/layout/navBar/FilesTree.vue')['default']
|
|
13
|
-
HamburgerButton: typeof import('./src/components/layout/HamburgerButton.vue')['default']
|
|
14
|
-
NavBar: typeof import('./src/components/layout/navBar/NavBar.vue')['default']
|
|
15
|
-
NavListItem: typeof import('./src/components/layout/navBar/NavListItem.vue')['default']
|
|
16
|
-
SearchBar: typeof import('./src/components/searchBar/SearchBar.vue')['default']
|
|
17
|
-
SearchResult: typeof import('./src/components/searchBar/SearchResult.vue')['default']
|
|
18
|
-
SlidesContent: typeof import('./src/components/SlidesContent.vue')['default']
|
|
19
|
-
TableOfContent: typeof import('./src/components/TableOfContent.vue')['default']
|
|
20
|
-
ThemeSwitcher: typeof import('./src/components/layout/ThemeSwitcher.vue')['default']
|
|
21
|
-
TopBar: typeof import('./src/components/layout/TopBar.vue')['default']
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="astro/client" />
|