@anydigital/blades 0.27.0-alpha.10

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.
@@ -0,0 +1,12 @@
1
+ {
2
+ "printWidth": 120,
3
+ "plugins": ["prettier-plugin-jinja-template"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.njk", "*.html"],
7
+ "options": {
8
+ "parser": "jinja-template"
9
+ }
10
+ }
11
+ ]
12
+ }
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Anton Staroverov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ 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, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,323 @@
1
+ # `blades`<sub><sup>`[.css|.njk|.liquid]`</sup></sub>
2
+
3
+ A graceful, semantic CSS extension for Pico or Tailwind, with Nunjucks/Liquid batteries included 🥷
4
+
5
+ <!--section:css-h2-->
6
+
7
+ ## CSS 'blades' <br><sub>from https://github.com/anydigital/blades</sub> <a id="blades"></a>
8
+
9
+ ### Install CSS
10
+
11
+ Via CDN:
12
+
13
+ ```html
14
+ <link href="https://cdn.jsdelivr.net/npm/@anydigital/blades@0/dist/blades.min.css" rel="stylesheet" />
15
+ ```
16
+
17
+ Or import source styles via npm:
18
+
19
+ ```sh
20
+ npm install @anydigital/blades
21
+ ```
22
+
23
+ ```css {data-caption=.css}
24
+ @import "@anydigital/blades";
25
+ ```
26
+
27
+ <details><summary>
28
+
29
+ ### `_base.css` styles
30
+
31
+ </summary>
32
+
33
+ #### Overflow Control
34
+
35
+ Prevents horizontal overflow and scrolling on the entire page:
36
+
37
+ ```css
38
+ html,
39
+ body {
40
+ overflow-x: clip;
41
+ }
42
+ ```
43
+
44
+ This is automatically applied when you include the stylesheet.
45
+
46
+ #### Full Viewport Height
47
+
48
+ Ensures the body element takes at least the full height of the viewport using dynamic viewport height for better mobile support:
49
+
50
+ ```css
51
+ body {
52
+ min-height: 100dvh;
53
+ }
54
+ ```
55
+
56
+ This is automatically applied when you include the stylesheet.
57
+
58
+ #### Flexbox Layout
59
+
60
+ Sets up a flexible column layout structure:
61
+
62
+ ```css
63
+ body {
64
+ display: flex;
65
+ flex-direction: column;
66
+ }
67
+
68
+ body > main {
69
+ flex-grow: 1;
70
+ }
71
+ ```
72
+
73
+ The body becomes a flex container with column direction, and `main` elements automatically grow to fill available space. This is useful for creating sticky footers and full-height layouts.
74
+
75
+ This is automatically applied when you include the stylesheet.
76
+
77
+ #### Typography Enhancements
78
+
79
+ Improves text rendering and readability:
80
+
81
+ ```css
82
+ body {
83
+ hyphens: auto;
84
+ -webkit-font-smoothing: antialiased;
85
+ -moz-osx-font-smoothing: grayscale;
86
+ }
87
+ ```
88
+
89
+ - Automatic hyphenation for better text flow
90
+ - Font smoothing for cleaner text rendering across browsers
91
+ - Hyphenation is disabled for links and tables to prevent awkward breaks
92
+
93
+ This is automatically applied when you include the stylesheet.
94
+
95
+ </details>
96
+
97
+ <details><summary>
98
+
99
+ ### `_prose.css` Tailwind Typography enhancements
100
+
101
+ </summary>
102
+
103
+ The `.prose` class provides enhanced typography for article content and long-form text with container-like behavior:
104
+
105
+ **Container:**
106
+
107
+ - Full width
108
+ - Centered with automatic inline margins
109
+
110
+ **Typography Helpers:**
111
+
112
+ - `sub` elements: styled for multi-line subtitles with top vertical alignment, `1.1` line height, lighter weight (`300`), and displayed as `inline-block` with `100%` width to prevent underline decoration inside links
113
+
114
+ **Links:**
115
+
116
+ - Custom underline offset (`0.1em`) and thickness (`1px` default, `2px` on hover)
117
+ - Anchor links (starting with `#`) have no text decoration
118
+ - Icon helper: `i` elements inside links are displayed as `inline-block` with normal font style to prevent underline decoration, with `1em` height and `0.25em` right margin. Nested `img` elements are styled with `100%` height, no margin, and positioned `0.15em` from the bottom for proper alignment
119
+
120
+ **Headings:**
121
+
122
+ - `h1` elements have a `0.5em` bottom margin
123
+ - `h1 sub` elements get reduced font size (`50%`)
124
+ - Support for heading anchors via `.header-anchor` class (displayed on hover to the left of the heading)
125
+
126
+ **Tables:**
127
+
128
+ - Tables within `.breakout` containers are automatically styled for full-bleed display and horizontal scrolling
129
+ - Table cells (`th` and `td`) have padding of `1rem 2rem 1rem 0` (extra space on the right for better horizontal scroll on mobile) and `top` vertical alignment
130
+ - Table headers (`th`) have `bottom` vertical alignment
131
+ - Workaround for widening columns using hidden `hr` elements (width: `12ch`, with zero margin and hidden visibility)
132
+ - Support for headings in Markdown tables using `big` elements (styled as bold)
133
+ - Images in table cells have no top margin and `1em` bottom margin
134
+
135
+ **Blockquotes:**
136
+
137
+ - Lighter font weight (`300`)
138
+ - Adjacent `figcaption` elements (using `+ figcaption` selector) are styled with italic text, right alignment, lighter weight (`300`), negative top margin (`-1em`), and an em dash prefix (`—`) with `0.25em` right margin
139
+
140
+ **Code Blocks:**
141
+
142
+ - Code blocks with `data-caption` attribute display the caption above the code block (styled with 50% opacity, italic, and `1.5em` bottom margin)
143
+
144
+ </details>
145
+
146
+ ### `_prism.css` enhancements
147
+
148
+ Includes specialized styling for Prism.js, specifically focusing on treeview components:
149
+
150
+ - Custom styling for `.token.treeview-part`
151
+ - Reduced opacity for entry lines (25%) and names (50%) to create a hierarchical visual effect
152
+ - Entry lines have a fixed width of `2.5em`
153
+ - Last-child entry names have no `::before` pseudo-element
154
+ - Supports complex file tree visualizations out of the box
155
+
156
+ <details><summary>
157
+
158
+ ### `_util.css` helpers
159
+
160
+ </summary>
161
+
162
+ #### Scrollbar Inversion
163
+
164
+ The `.invert` class can be used to invert the scrollbar colors, which is particularly useful for dark themes or specific UI components:
165
+
166
+ ```css
167
+ .invert {
168
+ ::-webkit-scrollbar {
169
+ filter: invert(1) !important;
170
+ }
171
+ }
172
+ ```
173
+
174
+ #### Link Whitespace Control
175
+
176
+ The `.whitespace-nowrap` class can be applied to links to prevent them from wrapping, which is particularly useful when links contain icons that should stay with the text:
177
+
178
+ ```html
179
+ <a href="#" class="whitespace-nowrap">
180
+ <i><img src="icon.svg" alt="" /></i>Stay with me
181
+ </a>
182
+ ```
183
+
184
+ This ensures the icon and the text stay together on the same line. If you need nested elements to allow wrapping, they are automatically reset to `white-space: normal`.
185
+
186
+ **Usage:**
187
+
188
+ ```html
189
+ <article class="prose">
190
+ <h1>Article Title</h1>
191
+ <p>Your content here...</p>
192
+ </article>
193
+ ```
194
+
195
+ This is automatically included when you import the stylesheet.
196
+
197
+ </details>
198
+
199
+ ### `breakout-css` included
200
+
201
+ Includes [breakout-css](https://github.com/anydigital/breakout-css) utilities for breaking out images and figures beyond their container width. Use the `.breakout` class to allow elements to extend beyond their parent container:
202
+
203
+ ```html
204
+ <div class="breakout">
205
+ <img src="image.jpg" alt="Description" />
206
+ </div>
207
+ ```
208
+
209
+ The breakout container has `10%` inline padding and a max-width of `calc(10% + 65ch + 10%)`. The breakout utilities support images, pictures, figures, canvas, audio, video, tables, pre, iframe, and other media elements. Tables inside `.breakout` are specifically enhanced for horizontal scrolling and full-bleed mobile display. This is automatically included when you import the stylesheet.
210
+
211
+ <!--section:njk-liquid-h2-->
212
+
213
+ ## Universal Template 'blades' <small>(`.njk` & `.liquid`)</small> <br><sub>from https://github.com/anydigital/blades</sub>
214
+
215
+ The package includes reusable templates in the `./src/blades/` directory. These are useful for common web development patterns.
216
+
217
+ ### Install Templates
218
+
219
+ ```sh
220
+ npm install @anydigital/blades
221
+ cd ./src/_includes
222
+ ln -s ../../node_modules/@anydigital/blades/src/blades
223
+ ```
224
+
225
+ ### Base HTML Template <small>(`__html.*`)</small>
226
+
227
+ A unified base HTML template `blades/__html.{njk|liquid}` that provides the essential document structure with built-in support for modern web best practices.
228
+
229
+ **Usage:**
230
+
231
+ ```jinja2 {data-caption="in .njk layout:"}
232
+ {% extends 'blades/__html.njk' %}
233
+
234
+ {% block body %}
235
+ <!-- YOUR page content -->
236
+ {% endblock %}
237
+ ```
238
+
239
+ Example: https://github.com/anydigital/sveleven/blob/main/src/_theme/__layout.njk
240
+
241
+ ```liquid {data-caption="in .liquid layout:"}
242
+ {% capture body %}
243
+ <!-- YOUR page content -->
244
+ {% endcapture %}
245
+
246
+ {% include 'blades/__html' %}
247
+ ```
248
+
249
+ Example: https://github.com/anydigital/sveleven/blob/main/src/_theme/__layout.liquid
250
+
251
+ **Features:**
252
+
253
+ - HTML5 DOCTYPE with language attribute (defaults to `en`, configurable via `site.lang`)
254
+ - UTF-8 charset and comprehensive viewport meta tag with `viewport-fit=cover` for notched devices
255
+ - Dynamic title generation with site title suffix (title is stripped of HTML tags and separated with `|`)
256
+ - Favicon link (to `/favicon.ico`)
257
+ - Automatic stylesheet linking from `site.styles` array
258
+ - Inline styles from `site.inline_styles` array (joined with newlines in a `<style>` tag)
259
+ - Automatic script loading from `site.scripts` array (with `defer` attribute)
260
+ - Inline module scripts from `site.inline_scripts` array (joined with newlines in a `<script type="module">` tag)
261
+ - Custom header content via `content_for_header`
262
+ - Google Tag Manager integration (automatically rendered via `_gtm.{njk|liquid}` template for both `<head>` and `<body>` when `site.prod` and `site.gtm_id` are set)
263
+
264
+ **Variables:**
265
+
266
+ - `body` - The page content to be rendered inside the `<body>` tag (required)
267
+ - `title` - Page title (optional, will be stripped of HTML tags)
268
+ - `site.title` - Site title for the title suffix
269
+ - `site.lang` - Language code (optional, defaults to `'en'`)
270
+ - `site.styles` - Array of stylesheet URLs (optional)
271
+ - `site.inline_styles` - Array of inline CSS strings (optional)
272
+ - `site.scripts` - Array of script URLs (optional)
273
+ - `site.inline_scripts` - Array of inline JavaScript strings (optional)
274
+ - `content_for_header` - Custom HTML for the head section (optional)
275
+ - `site.gtm_id` - Google Tag Manager ID (optional)
276
+ - `site.prod` - Boolean flag for production environment (optional)
277
+
278
+ ### Navigation <small>(`_nav.*`)</small>
279
+
280
+ A navigation template `blades/_nav.{njk|liquid}` that renders a list of navigation links with proper accessibility attributes.
281
+
282
+ **Parameters:**
283
+
284
+ - `nav_pages` - Array of navigation page objects with `url` and `title` properties
285
+ - `current_url` - The URL of the current page (used to set `aria-current="page"`)
286
+
287
+ **Usage example with [Eleventy Navigation plugin](https://www.11ty.dev/docs/plugins/navigation/#bring-your-own-html-render-the-menu-items-manually):**
288
+
289
+ ```liquid {data-caption="in .liquid:"}
290
+ {% assign nav_pages = collections.all | eleventyNavigation %}
291
+ {% render 'blades/_nav', nav_pages: nav_pages, current_url: page.url %}
292
+ ```
293
+
294
+ **Output:**
295
+
296
+ ```html
297
+ <nav>
298
+ <a href="/">Home</a>
299
+ <a href="/about" aria-current="page">About</a>
300
+ <a href="/contact">Contact</a>
301
+ </nav>
302
+ ```
303
+
304
+ <details><summary>
305
+
306
+ ### Google Tag Manager <small>(`_gtm.*`)</small>
307
+
308
+ </summary>
309
+
310
+ A template `blades/_gtm.{njk|liquid}` for embedding Google Tag Manager scripts in your pages.
311
+
312
+ **Parameters:**
313
+
314
+ - `site.gtm_id` - Your Google Tag Manager container ID (e.g., `GTM-XXXXXXX`)
315
+ - `site.prod` - Boolean flag to enable GTM only in production
316
+ - `for_body` - Boolean flag (default: `false`). When `false`, renders the script tag for the `<head>`. When `true`, renders the noscript fallback for the `<body>`.
317
+
318
+ **Note:** This template is automatically included when using `__html.liquid`. You only need to manually render it if you're not using that base template, see examples:
319
+
320
+ - https://github.com/anydigital/blades/blob/main/blades/__html.njk
321
+ - https://github.com/anydigital/blades/blob/main/blades/__html.liquid
322
+
323
+ </details>
package/_config.yml ADDED
@@ -0,0 +1,5 @@
1
+ exclude:
2
+ - "**/*"
3
+ include:
4
+ - "assets/**/*"
5
+ - "*.md"
@@ -0,0 +1,23 @@
1
+ {% if site.prod and site.gtm_id %}
2
+ {% capture _ %}
3
+ {% unless for_body %}
4
+
5
+ <!-- Google Tag Manager -->
6
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
7
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
8
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
9
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
10
+ })(window,document,'script','dataLayer','{{ site.gtm_id }}');</script>
11
+ <!-- End Google Tag Manager -->
12
+
13
+ {% else %}
14
+
15
+ <!-- Google Tag Manager (noscript) -->
16
+ <noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ site.gtm_id }}"
17
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
18
+ <!-- End Google Tag Manager (noscript) -->
19
+
20
+ {% endunless %}
21
+ {% endcapture %}
22
+ {{ _ | strip }}
23
+ {% endif %}
@@ -0,0 +1,22 @@
1
+ {% if site.prod and site.gtm_id %}
2
+ {# prettier-ignore-start #}
3
+ {% if not for_body %}
4
+
5
+ <!-- Google Tag Manager -->
6
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
7
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
8
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
9
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
10
+ })(window,document,'script','dataLayer','{{ site.gtm_id }}');</script>
11
+ <!-- End Google Tag Manager -->
12
+
13
+ {% else %}
14
+
15
+ <!-- Google Tag Manager (noscript) -->
16
+ <noscript><iframe src="https://www.googletagmanager.com/ns.html?id={{ site.gtm_id }}"
17
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
18
+ <!-- End Google Tag Manager (noscript) -->
19
+
20
+ {% endif %}
21
+ {# prettier-ignore-end #}
22
+ {% endif %}
@@ -0,0 +1,36 @@
1
+ <!doctype html>
2
+ <html lang="{{ site.lang | default: 'en' }}">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover">
6
+ <link rel="icon" href="{{ site.favicon | default: '/favicon.ico' }}">
7
+ <title>
8
+ {%- if title %}{{ title | strip_html | append: ' | ' }}{% endif -%}
9
+ {{- site.title -}}
10
+ </title>
11
+ <meta name="description" content="{{ page.description }}">
12
+
13
+ {%- for href in site.styles %}
14
+ <link rel="stylesheet" href="{{ href | relative_url }}">
15
+ {%- endfor %}
16
+ <style>
17
+ {{ site.inline_styles | join: '\n' }}
18
+ </style>
19
+
20
+ {%- for src in site.scripts %}
21
+ <script src="{{ src }}" defer></script>
22
+ {%- endfor %}
23
+ <script type="module">
24
+ {{ site.inline_scripts | join: '\n' }}
25
+ </script>
26
+
27
+ {{ content_for_header }}
28
+ {% include blades/gtm.liquid %}
29
+ </head>
30
+
31
+ <body>
32
+ {% include blades/gtm.liquid for_body=true %}
33
+
34
+ {{ body }}
35
+ </body>
36
+ </html>
@@ -0,0 +1,36 @@
1
+ <!doctype html>
2
+ <html lang="{{ site.lang | d('en') }}">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover" />
6
+ <link rel="icon" href="{{ site.favicon | d('/favicon.ico') }}" />
7
+ <title>
8
+ {{- title | strip_html ~ ' | ' if title -}}
9
+ {{- site.title -}}
10
+ </title>
11
+ <meta name="description" content="{{ page.description }}" />
12
+
13
+ {%- for href in site.styles %}
14
+ <link rel="stylesheet" href="{{ href }}" />
15
+ {%- endfor %}
16
+ {# prettier-ignore-start #}<style>
17
+ {{ site.inline_styles | d([]) | join('\n') }}
18
+ </style>{# prettier-ignore-end #}
19
+
20
+ {%- for src in site.scripts %}
21
+ <script src="{{ src }}" defer></script>
22
+ {%- endfor %}
23
+ {# prettier-ignore-start #}<script type="module">
24
+ {{ site.inline_scripts | d([]) | join('\n') }}
25
+ </script>{# prettier-ignore-end #}
26
+
27
+ {{ content_for_header }}
28
+ {% include 'blades/gtm.njk' %}
29
+ </head>
30
+
31
+ <body>
32
+ {% set for_body = true %}{% include 'blades/gtm.njk' %}
33
+ {% block body %}
34
+ {% endblock %}
35
+ </body>
36
+ </html>
@@ -0,0 +1,14 @@
1
+ <nav>
2
+ {%- for entry in nav_pages %}
3
+ {% # prettier-ignore %}
4
+ <a href="{{ entry.url }}" {% if entry.url == current_url %}aria-current="page"{% endif %}>
5
+ {{- entry.title -}}
6
+ </a>
7
+ {%- endfor %}
8
+ </nav>
9
+
10
+ {%- comment %}
11
+ Compatible with:
12
+ - https://picocss.com/docs/nav
13
+ - https://www.11ty.dev/docs/plugins/navigation/#bring-your-own-html-render-the-menu-items-manually
14
+ {%- endcomment %}