starlight-cannoli-plugins 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -6,13 +6,22 @@ A collection of powerful plugins for [Astro Starlight](https://starlight.astro.b
|
|
|
6
6
|
|
|
7
7
|
### Starlight Index-Only Sidebar
|
|
8
8
|
|
|
9
|
-
Automatically generates
|
|
9
|
+
Automatically generates a nested Starlight sidebar by recursively scanning directories for `index.md`/`index.mdx` files. Only directories with index files appear in the sidebar, creating a clean, minimal navigation structure.
|
|
10
10
|
|
|
11
11
|
**Features:**
|
|
12
|
-
-
|
|
12
|
+
- Recursively scans directories for `index.md` or `index.mdx` files
|
|
13
|
+
- Creates sidebar entries only for pages with index files
|
|
13
14
|
- Respects frontmatter: `draft: true` and `sidebar.hidden: true` hide entries
|
|
14
|
-
-
|
|
15
|
-
-
|
|
15
|
+
- Automatically collapses single-child groups (no intermediate wrappers)
|
|
16
|
+
- Configurable depth limiting to flatten deeply nested content
|
|
17
|
+
- Two labeling modes: directory names or frontmatter titles
|
|
18
|
+
- Ignores `assets` directories entirely
|
|
19
|
+
|
|
20
|
+
**Options:**
|
|
21
|
+
|
|
22
|
+
- `directories` (required): Array of directory names to scan (e.g., `["guides", "api"]`)
|
|
23
|
+
- `maxDepthNesting` (optional, default: `100`): Maximum nesting depth. Root is level 0. At max depth, deeper index files are flattened as sibling items.
|
|
24
|
+
- `dirnameDeterminesLabels` (optional, default: `true`): When `true`, all labels use raw directory names. When `false`, slug item labels come from frontmatter `title` field; group labels still use directory names.
|
|
16
25
|
|
|
17
26
|
**Usage:**
|
|
18
27
|
|
|
@@ -28,11 +37,9 @@ export default defineConfig({
|
|
|
28
37
|
title: "My Docs",
|
|
29
38
|
plugins: [
|
|
30
39
|
starlightIndexOnlySidebar({
|
|
31
|
-
directories: [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
],
|
|
35
|
-
dirnameDeterminesLabel: false, // optional: use directory names as labels
|
|
40
|
+
directories: ["guides", "api", "tutorials"],
|
|
41
|
+
maxDepthNesting: 2, // optional
|
|
42
|
+
dirnameDeterminesLabels: false, // optional
|
|
36
43
|
}),
|
|
37
44
|
],
|
|
38
45
|
}),
|
|
@@ -50,6 +57,7 @@ A rehype plugin that validates all internal links in your Markdown/MDX files at
|
|
|
50
57
|
- Auto-expands extensionless links to match `.md` or `.mdx` files
|
|
51
58
|
- Converts internal links to site-absolute paths
|
|
52
59
|
- Throws build errors for broken links
|
|
60
|
+
- Skip validation for forward-reference links using multiple approaches
|
|
53
61
|
|
|
54
62
|
**Usage:**
|
|
55
63
|
|
|
@@ -73,6 +81,48 @@ Or import directly:
|
|
|
73
81
|
import { rehypeValidateLinks } from "cannoli-starlight-plugins/rehype-validate-links";
|
|
74
82
|
```
|
|
75
83
|
|
|
84
|
+
**Skipping Link Validation:**
|
|
85
|
+
|
|
86
|
+
There are three ways to skip validation for specific links:
|
|
87
|
+
|
|
88
|
+
**1. Question Mark Prefix** (Per-link, in markdown)
|
|
89
|
+
|
|
90
|
+
Prepend a `?` to the link href to skip validation:
|
|
91
|
+
|
|
92
|
+
```mdx
|
|
93
|
+
[Grade Calculator](?csci-320-331-obrenic/grade-calculator)
|
|
94
|
+
[Grade Calculator](?./csci-320-331-obrenic/grade-calculator)
|
|
95
|
+
[Grade Calculator](?/csci-320-331-obrenic/grade-calculator)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**2. HTML Data Attribute** (Per-link, requires HTML syntax)
|
|
99
|
+
|
|
100
|
+
Use the `data-no-link-check` attribute on anchor tags:
|
|
101
|
+
|
|
102
|
+
```mdx
|
|
103
|
+
<a href="csci-320-331-obrenic/grade-calculator" data-no-link-check>Grade Calculator</a>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**3. Global Skip Patterns** (Configuration-based)
|
|
107
|
+
|
|
108
|
+
Use the `skipPatterns` option to exclude links matching glob patterns:
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
// astro.config.mjs
|
|
112
|
+
export default defineConfig({
|
|
113
|
+
markdown: {
|
|
114
|
+
rehypePlugins: [
|
|
115
|
+
[rehypeValidateLinks, {
|
|
116
|
+
skipPatterns: [
|
|
117
|
+
'/csci-320-331-obrenic/grade-calculator', // exact match
|
|
118
|
+
'**/draft-*', // glob pattern
|
|
119
|
+
]
|
|
120
|
+
}],
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
76
126
|
## Installation
|
|
77
127
|
|
|
78
128
|
```bash
|
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
// src/plugins/rehype-validate-links.ts
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { sync as globSync } from "glob";
|
|
4
|
+
import { minimatch } from "minimatch";
|
|
4
5
|
import { dirname, join, relative, resolve } from "path";
|
|
5
6
|
import { visit } from "unist-util-visit";
|
|
6
7
|
var PROJECT_DOCS_DIR = "src/content/docs";
|
|
8
|
+
function matchesSkipPattern(path, patterns) {
|
|
9
|
+
if (!patterns || patterns.length === 0) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return patterns.some((pattern) => minimatch(path, pattern));
|
|
13
|
+
}
|
|
7
14
|
function getResolvedLink(href, currentFilePath) {
|
|
15
|
+
let skipValidation = false;
|
|
16
|
+
let processedHref = href;
|
|
17
|
+
if (href.startsWith("?")) {
|
|
18
|
+
skipValidation = true;
|
|
19
|
+
processedHref = href.slice(1);
|
|
20
|
+
}
|
|
8
21
|
try {
|
|
9
|
-
new URL(
|
|
22
|
+
new URL(processedHref);
|
|
10
23
|
return null;
|
|
11
24
|
} catch {
|
|
12
25
|
}
|
|
13
|
-
if (!
|
|
26
|
+
if (!processedHref) {
|
|
14
27
|
return null;
|
|
15
28
|
}
|
|
16
|
-
const fragmentMatch =
|
|
29
|
+
const fragmentMatch = processedHref.split("#");
|
|
17
30
|
const withoutFragment = fragmentMatch[0];
|
|
18
31
|
const fragment = fragmentMatch[1] || "";
|
|
19
32
|
if (!withoutFragment) {
|
|
@@ -46,7 +59,8 @@ function getResolvedLink(href, currentFilePath) {
|
|
|
46
59
|
original_href: href,
|
|
47
60
|
project_absolute_href: finalProjectAbsoluteHref,
|
|
48
61
|
site_absolute_href: siteAbsoluteHref,
|
|
49
|
-
fragment
|
|
62
|
+
fragment,
|
|
63
|
+
skipValidation
|
|
50
64
|
};
|
|
51
65
|
}
|
|
52
66
|
function validateLink(link) {
|
|
@@ -73,7 +87,7 @@ function validateLink(link) {
|
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
89
|
}
|
|
76
|
-
function rehypeValidateLinks() {
|
|
90
|
+
function rehypeValidateLinks(options) {
|
|
77
91
|
return (tree, file) => {
|
|
78
92
|
const filePath = file.path;
|
|
79
93
|
if (!filePath) {
|
|
@@ -82,7 +96,7 @@ function rehypeValidateLinks() {
|
|
|
82
96
|
);
|
|
83
97
|
return;
|
|
84
98
|
}
|
|
85
|
-
visit(tree, "element", (node) => {
|
|
99
|
+
visit(tree, "element", (node, index, parent) => {
|
|
86
100
|
let resourcePath;
|
|
87
101
|
let attributeName = null;
|
|
88
102
|
if (node.tagName === "a") {
|
|
@@ -95,6 +109,29 @@ function rehypeValidateLinks() {
|
|
|
95
109
|
if (!resourcePath || !attributeName) return;
|
|
96
110
|
const link = getResolvedLink(resourcePath, filePath);
|
|
97
111
|
if (!link) return;
|
|
112
|
+
if (link.skipValidation) {
|
|
113
|
+
node.properties = node.properties || {};
|
|
114
|
+
node.properties[attributeName] = link.site_absolute_href;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (node.properties?.["data-no-link-check"] !== void 0) {
|
|
118
|
+
node.properties = node.properties || {};
|
|
119
|
+
node.properties[attributeName] = link.site_absolute_href;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (matchesSkipPattern(link.site_absolute_href, options?.skipPatterns)) {
|
|
123
|
+
node.properties = node.properties || {};
|
|
124
|
+
node.properties[attributeName] = link.site_absolute_href;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (index !== void 0 && parent && "children" in parent && Array.isArray(parent.children)) {
|
|
128
|
+
const nextNode = parent.children[index + 1];
|
|
129
|
+
if (nextNode && "type" in nextNode && nextNode.type === "comment" && "value" in nextNode && typeof nextNode.value === "string" && nextNode.value.includes("no-link-check")) {
|
|
130
|
+
node.properties = node.properties || {};
|
|
131
|
+
node.properties[attributeName] = link.site_absolute_href;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
98
135
|
validateLink(link);
|
|
99
136
|
node.properties = node.properties || {};
|
|
100
137
|
node.properties[attributeName] = link.site_absolute_href;
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Root } from 'hast';
|
|
2
2
|
import { VFile } from 'vfile';
|
|
3
3
|
|
|
4
|
+
type TRehypeValidateLinksOptions = {
|
|
5
|
+
skipPatterns?: string[];
|
|
6
|
+
};
|
|
4
7
|
/**
|
|
5
8
|
* Rehype plugin to validate all internal links and convert them to absolute paths
|
|
6
9
|
*/
|
|
7
|
-
declare function rehypeValidateLinks(): (tree: Root, file: VFile) => void;
|
|
10
|
+
declare function rehypeValidateLinks(options?: TRehypeValidateLinksOptions): (tree: Root, file: VFile) => void;
|
|
8
11
|
|
|
9
12
|
export { rehypeValidateLinks as default, rehypeValidateLinks };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "starlight-cannoli-plugins",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"description": "Starlight plugins for automatic sidebar generation and link validation",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -18,10 +18,13 @@
|
|
|
18
18
|
"./rehype-validate-links": {
|
|
19
19
|
"import": "./dist/plugins/rehype-validate-links.js",
|
|
20
20
|
"types": "./dist/plugins/rehype-validate-links.d.ts"
|
|
21
|
-
}
|
|
21
|
+
},
|
|
22
|
+
"./styles": "./src/styles/",
|
|
23
|
+
"./styles/*": "./src/styles/*"
|
|
22
24
|
},
|
|
23
25
|
"files": [
|
|
24
|
-
"dist"
|
|
26
|
+
"dist",
|
|
27
|
+
"src/styles"
|
|
25
28
|
],
|
|
26
29
|
"keywords": [
|
|
27
30
|
"astro",
|
|
@@ -49,6 +52,7 @@
|
|
|
49
52
|
},
|
|
50
53
|
"dependencies": {
|
|
51
54
|
"glob": "^13.0.6",
|
|
55
|
+
"minimatch": "^10.2.4",
|
|
52
56
|
"unist-util-visit": "^5.0.0",
|
|
53
57
|
"yaml": "^2.4.0"
|
|
54
58
|
},
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
$info-color: #3b82f6;
|
|
2
|
+
$warning-color: #f59e0b;
|
|
3
|
+
|
|
4
|
+
html {
|
|
5
|
+
scroll-behavior: smooth;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// invert img.note-svg when on dark mode
|
|
9
|
+
img.note-svg {
|
|
10
|
+
color-scheme: light dark;
|
|
11
|
+
padding-top: 1em;
|
|
12
|
+
padding-bottom: 1em;
|
|
13
|
+
|
|
14
|
+
html[data-theme="light"] & {
|
|
15
|
+
filter: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
html:not([data-theme="light"]) & {
|
|
19
|
+
filter: invert(1) hue-rotate(180deg);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/************ Starlight Additions/Overrides ************/
|
|
24
|
+
|
|
25
|
+
.sl-container:where(.astro-7nkwcw3z) {
|
|
26
|
+
max-width: 50rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.main-pane {
|
|
30
|
+
table > thead > tr > th {
|
|
31
|
+
border-bottom: 1px solid hsl(228, 6.2%, 47.3%);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
starlight-toc {
|
|
36
|
+
a {
|
|
37
|
+
transition: transform 0.2s ease;
|
|
38
|
+
transform-origin: left;
|
|
39
|
+
|
|
40
|
+
span {
|
|
41
|
+
position: relative;
|
|
42
|
+
display: inline-block;
|
|
43
|
+
transition: color 0.2s ease;
|
|
44
|
+
|
|
45
|
+
&::before {
|
|
46
|
+
content: "";
|
|
47
|
+
position: absolute;
|
|
48
|
+
left: -8px;
|
|
49
|
+
top: 0;
|
|
50
|
+
bottom: 0;
|
|
51
|
+
width: 3px;
|
|
52
|
+
background-color: transparent;
|
|
53
|
+
border-radius: 2px;
|
|
54
|
+
transition: background-color 0.2s ease;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
a[aria-current="true"] {
|
|
60
|
+
transform: scale(1.04);
|
|
61
|
+
|
|
62
|
+
span {
|
|
63
|
+
&::before {
|
|
64
|
+
background-color: var(--sl-color-text-accent);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#starlight__search mark {
|
|
71
|
+
color: hsl(339.8, 63.4%, 60.4%);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#starlight__mobile-toc {
|
|
75
|
+
> .dropdown {
|
|
76
|
+
border-bottom: 1px solid hsla(0, 0%, 100%, 0.6);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.expressive-code .copy > button {
|
|
81
|
+
height: 2rem;
|
|
82
|
+
width: 2rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/************ Details/Summary Styles ************/
|
|
86
|
+
.main-pane details {
|
|
87
|
+
background: var(--sl-color-bg-nav);
|
|
88
|
+
border-radius: 4px;
|
|
89
|
+
padding: 0.3rem 0.6rem;
|
|
90
|
+
display: block;
|
|
91
|
+
|
|
92
|
+
&[open] {
|
|
93
|
+
max-width: 100%;
|
|
94
|
+
|
|
95
|
+
> div.details-wrapper {
|
|
96
|
+
overflow: auto;
|
|
97
|
+
max-height: 67vh;
|
|
98
|
+
padding-right: 0.8rem;
|
|
99
|
+
padding-left: 0.8rem;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
p > img {
|
|
103
|
+
height: auto;
|
|
104
|
+
width: auto;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/********** MathJax/LaTeX Styling **********/
|
|
110
|
+
mjx-container[jax="SVG"] {
|
|
111
|
+
overflow-x: auto;
|
|
112
|
+
|
|
113
|
+
&[display="true"] {
|
|
114
|
+
margin-top: 0.7em !important;
|
|
115
|
+
margin-bottom: 0.7em !important;
|
|
116
|
+
padding-top: 0.3em;
|
|
117
|
+
padding-bottom: 0.3em;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
> svg {
|
|
121
|
+
display: unset;
|
|
122
|
+
max-width: unset;
|
|
123
|
+
height: unset;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/********** TikZ SVG Styling **********/
|
|
128
|
+
script[type="text/tikz"] {
|
|
129
|
+
display: block;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
div > div[class="page"] > svg {
|
|
133
|
+
color-scheme: light dark;
|
|
134
|
+
|
|
135
|
+
html[data-theme="light"] & {
|
|
136
|
+
stroke: currentColor;
|
|
137
|
+
fill: currentColor;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
html:not([data-theme="light"]) & {
|
|
141
|
+
stroke: white;
|
|
142
|
+
fill: white;
|
|
143
|
+
filter: invert(1) hue-rotate(180deg);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/********** Mimic Bootstrap Class Utilities **********/
|
|
148
|
+
.visually-hidden {
|
|
149
|
+
display: none !important;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.visibility-hidden {
|
|
153
|
+
visibility: hidden !important;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.visible {
|
|
157
|
+
display: block !important;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.text-center {
|
|
161
|
+
text-align: center !important;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.d-block {
|
|
165
|
+
display: block !important;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.d-flex {
|
|
169
|
+
display: flex !important;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.flex-row {
|
|
173
|
+
flex-direction: row !important;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.flex-column {
|
|
177
|
+
flex-direction: column !important;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.justify-content-center {
|
|
181
|
+
justify-content: center !important;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.justify-content-between {
|
|
185
|
+
justify-content: space-between !important;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.justify-content-around {
|
|
189
|
+
justify-content: space-around !important;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.justify-content-evenly {
|
|
193
|
+
justify-content: space-evenly !important;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.align-items-center {
|
|
197
|
+
align-items: center !important;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.align-items-start {
|
|
201
|
+
align-items: flex-start !important;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.flex-wrap {
|
|
205
|
+
flex-wrap: wrap !important;
|
|
206
|
+
|
|
207
|
+
.flex-fill {
|
|
208
|
+
flex: 1 1 auto;
|
|
209
|
+
margin-top: unset;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.flex-fill.flex-code {
|
|
213
|
+
min-width: 0;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.flex-grow-1 {
|
|
218
|
+
flex-grow: 1 !important;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* Overflow utilities */
|
|
222
|
+
.overflow-auto {
|
|
223
|
+
overflow: auto !important;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.overflow-y-auto {
|
|
227
|
+
overflow-y: auto !important;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.overflow-x-hidden {
|
|
231
|
+
overflow-x: hidden !important;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Padding and Margin Utilities */
|
|
235
|
+
/* Exposes utility classes like .p-0, .p-1, .pt-2, .mb-3, ..., .m-6, .gap-6 */
|
|
236
|
+
|
|
237
|
+
$spacings: (
|
|
238
|
+
p: padding,
|
|
239
|
+
pt: padding-top,
|
|
240
|
+
pb: padding-bottom,
|
|
241
|
+
ps: padding-left,
|
|
242
|
+
pe: padding-right,
|
|
243
|
+
m: margin,
|
|
244
|
+
mt: margin-top,
|
|
245
|
+
mb: margin-bottom,
|
|
246
|
+
ms: margin-left,
|
|
247
|
+
me: margin-right,
|
|
248
|
+
gap: gap,
|
|
249
|
+
gap-row: row-gap,
|
|
250
|
+
gap-col: column-gap,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
$axis-spacings: (
|
|
254
|
+
px: (
|
|
255
|
+
padding-left,
|
|
256
|
+
padding-right,
|
|
257
|
+
),
|
|
258
|
+
py: (
|
|
259
|
+
padding-top,
|
|
260
|
+
padding-bottom,
|
|
261
|
+
),
|
|
262
|
+
mx: (
|
|
263
|
+
margin-left,
|
|
264
|
+
margin-right,
|
|
265
|
+
),
|
|
266
|
+
my: (
|
|
267
|
+
margin-top,
|
|
268
|
+
margin-bottom,
|
|
269
|
+
),
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
@each $class, $property in $spacings {
|
|
273
|
+
.#{$class}-0 {
|
|
274
|
+
#{$property}: 0 !important;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
$scalar: 0.125;
|
|
278
|
+
$accumulated: 0;
|
|
279
|
+
|
|
280
|
+
@for $i from 1 through 6 {
|
|
281
|
+
$scalar: $scalar + ($i % 2) * $scalar;
|
|
282
|
+
$accumulated: $accumulated + $scalar;
|
|
283
|
+
|
|
284
|
+
.#{$class}-#{$i} {
|
|
285
|
+
#{$property}: #{$accumulated}rem !important;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* Axis-specific spacing utilities (-x and -y) */
|
|
291
|
+
@each $class, $properties in $axis-spacings {
|
|
292
|
+
.#{$class}-0 {
|
|
293
|
+
@each $property in $properties {
|
|
294
|
+
#{$property}: 0 !important;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
$scalar: 0.125;
|
|
299
|
+
$accumulated: 0;
|
|
300
|
+
|
|
301
|
+
@for $i from 1 through 6 {
|
|
302
|
+
$scalar: $scalar + ($i % 2) * $scalar;
|
|
303
|
+
$accumulated: $accumulated + $scalar;
|
|
304
|
+
|
|
305
|
+
.#{$class}-#{$i} {
|
|
306
|
+
@each $property in $properties {
|
|
307
|
+
#{$property}: #{$accumulated}rem !important;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/************ Custom Styles ************/
|
|
314
|
+
|
|
315
|
+
.highlight-green,
|
|
316
|
+
.highlight-red {
|
|
317
|
+
padding: 5px;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.highlight-green {
|
|
321
|
+
background: #7de37d34;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.highlight-red {
|
|
325
|
+
background: #f7535b46;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.admin-only {
|
|
329
|
+
display: none;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.note-indicator {
|
|
333
|
+
display: inline-block;
|
|
334
|
+
width: 8px;
|
|
335
|
+
height: 8px;
|
|
336
|
+
border-radius: 50%;
|
|
337
|
+
background-color: $info-color;
|
|
338
|
+
margin-right: 6px;
|
|
339
|
+
vertical-align: middle;
|
|
340
|
+
opacity: 0.6;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
div.note {
|
|
344
|
+
display: none;
|
|
345
|
+
border: 3px solid $warning-color;
|
|
346
|
+
border-left: 6px solid $warning-color;
|
|
347
|
+
padding: 12px;
|
|
348
|
+
border-radius: 4px;
|
|
349
|
+
margin: 10px 0;
|
|
350
|
+
|
|
351
|
+
&::before {
|
|
352
|
+
content: "Personal Note";
|
|
353
|
+
display: block;
|
|
354
|
+
font-weight: bold;
|
|
355
|
+
color: $info-color;
|
|
356
|
+
margin-bottom: 8px;
|
|
357
|
+
font-size: 0.95em;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/********** Toggle Checkbox Styles **********/
|
|
362
|
+
#toggle-all-details-btn {
|
|
363
|
+
display: flex;
|
|
364
|
+
align-items: center;
|
|
365
|
+
gap: 0.5rem;
|
|
366
|
+
cursor: pointer;
|
|
367
|
+
|
|
368
|
+
input[type="checkbox"] {
|
|
369
|
+
position: relative;
|
|
370
|
+
appearance: none;
|
|
371
|
+
width: 1.2em;
|
|
372
|
+
height: 1.2em;
|
|
373
|
+
border: 2px solid currentColor;
|
|
374
|
+
border-radius: 2px;
|
|
375
|
+
cursor: pointer;
|
|
376
|
+
display: flex;
|
|
377
|
+
align-items: center;
|
|
378
|
+
justify-content: center;
|
|
379
|
+
transition: background-color 0.2s ease;
|
|
380
|
+
|
|
381
|
+
&:checked {
|
|
382
|
+
background-color: var(--sl-color-accent);
|
|
383
|
+
border-color: var(--sl-color-accent);
|
|
384
|
+
|
|
385
|
+
&::after {
|
|
386
|
+
content: "✓";
|
|
387
|
+
color: white;
|
|
388
|
+
font-size: 0.8em;
|
|
389
|
+
font-weight: bold;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|