@luz-ds/cms 0.0.0-stage → 0.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.
- package/LICENSE +21 -0
- package/README.md +93 -2
- package/dist/classes.json +35 -0
- package/dist/cms.css +409 -0
- package/dist/cms.min.css +1 -0
- package/dist/components/article-header.css +95 -0
- package/dist/components/article-header.min.css +1 -0
- package/dist/components/article.css +88 -0
- package/dist/components/article.min.css +1 -0
- package/dist/components/footer.css +29 -0
- package/dist/components/footer.min.css +1 -0
- package/dist/components/header.css +155 -0
- package/dist/components/header.min.css +1 -0
- package/dist/components/page-header.css +41 -0
- package/dist/components/page-header.min.css +1 -0
- package/package.json +53 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024–2026 Fernando Muñoz
|
|
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
CHANGED
|
@@ -1,3 +1,94 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @luz-ds/cms
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The page structure of one kind of site, a blog, a newspaper or any site of articles, built with any CMS and any stack: the header (a bar or a newspaper's masthead), the page header, the article header, the table of contents beside the text, and the footer. Each is a class on a native element, laid out in the markup by `@luz-ds/core`'s objects (`.o-page`, `.o-sticky`, `.o-container`, `.o-row`, `.o-stack`) and its navbar; cms adds only its skin. `@luz-ds/catalog` is optional: its search and language switch go in the header's actions.
|
|
4
|
+
|
|
5
|
+
> **Beta, version 0.x.** CMS has a version of its own, apart from tokens, core and catalog, and grows in minor versions while it is 0.x: any of them may change a class. Pin an exact version and read the changelog before you upgrade.
|
|
6
|
+
|
|
7
|
+
## When to use it
|
|
8
|
+
|
|
9
|
+
- You publish articles, posts or stories, each with a title, an author and a date, some long enough to need a table of contents.
|
|
10
|
+
- Not for a landing page (`@luz-ds/landing`), documentation or an app.
|
|
11
|
+
|
|
12
|
+
The classes go on any element, so a template of any CMS can write them (in a block-editor template, a block's `className`). The post card, the post listing, related posts and the author box need no CSS of their own: they are markup to copy, built from core's card, avatar and pagination, on the [CMS templates](https://nandovejer.github.io/luz/docs/cms/templates/) page of the docs.
|
|
13
|
+
|
|
14
|
+
## Prerequisites
|
|
15
|
+
|
|
16
|
+
Requires `@luz-ds/tokens` and `@luz-ds/core`, version `^0.1.0 || ^0.2.0`, declared as peer dependencies, loaded in that order before this package. `@luz-ds/catalog` (`^0.1.0 || ^0.2.0`) is an optional peer: load it before this package if you use its pieces; the patterns work without it.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @luz-ds/tokens @luz-ds/core @luz-ds/catalog @luz-ds/cms
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Via npm/bundler
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import '@luz-ds/tokens/css'
|
|
30
|
+
import '@luz-ds/core/css'
|
|
31
|
+
import '@luz-ds/catalog/css'
|
|
32
|
+
import '@luz-ds/cms/css'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Via CDN
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/tokens@0.1.0/dist/luz-tokens.min.css">
|
|
39
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/core@0.1.0/dist/luz.min.css">
|
|
40
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.1.0/dist/catalog.min.css">
|
|
41
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/cms@0.1.0/dist/cms.min.css">
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
There is no script: the header's menu is a native popover. Core's script is optional: with it, the table of contents marks the section in view (core's scroll spy, on the in-page links inside an element with `data-luz-spy`).
|
|
45
|
+
|
|
46
|
+
The body of a story is core's `.luz-prose` (line length and the space between blocks) and its date and reading time are core's `.luz-meta`; lists of posts are core's `.o-grid` or `.o-stack` on a `<ul>`. None of them needs a rule of yours.
|
|
47
|
+
|
|
48
|
+
## Package exports
|
|
49
|
+
|
|
50
|
+
- **`./css`** → `cms.css` — the patterns, in the cascade layer `luz.cms`, after `luz.catalog` (`./css/min` for the minified twin)
|
|
51
|
+
- **`./components/*`** → `dist/components/` — one stylesheet per pattern, `<name>.css` and `<name>.min.css`, each in `luz.cms`, for a page that loads only what it uses
|
|
52
|
+
|
|
53
|
+
## Classes included
|
|
54
|
+
|
|
55
|
+
- `.luz-cms-header` (`__brand`, `__actions`; `--masthead` with `__top`, `__date`, `__sections`) — The top of every page: the publication's name, its sections in core's navbar and the actions, in one row that stays at the top with core's `.o-sticky`; or, with `--masthead`, a newspaper's three rows (date and search, the name, the sections), not sticky. [Docs](https://nandovejer.github.io/luz/docs/cms/header/)
|
|
56
|
+
- `.luz-cms-page-header` (`__title`, `__lead`) — The title of a page that is not an article (about, contact) and one sentence about what it is for. [Docs](https://nandovejer.github.io/luz/docs/cms/page-header/)
|
|
57
|
+
|
|
58
|
+
- `.luz-cms-article-header` (`__kicker`, `__title`, `__standfirst`, `__byline`, `__media`) — The top of a story: its section, the title, the standfirst, who wrote it and when, and an optional lead picture. [Docs](https://nandovejer.github.io/luz/docs/cms/article-header/)
|
|
59
|
+
- `.luz-cms-article` (`__layout`) and `.luz-cms-toc` (`__title`, `__list`) — The story and its table of contents: beside the text, staying in view, when the article is 46rem wide or more; above it below that. `--luz-cms-toc-top` sets the space above it while it stays in view (by default under a `.o-sticky` bar of core's `--luz-bar-h`). [Docs](https://nandovejer.github.io/luz/docs/cms/toc/)
|
|
60
|
+
- `.luz-cms-footer` — The end of every page: a rule above, who publishes it and a few links at the two ends of a row; a column at 768 px and below. [Docs](https://nandovejer.github.io/luz/docs/cms/footer/)
|
|
61
|
+
|
|
62
|
+
<!-- luz:ai-agents:start -->
|
|
63
|
+
## For AI agents
|
|
64
|
+
|
|
65
|
+
`@luz-ds/cms` 0.2.0 is in beta: any release may break anything. Read the breaking changes below before you update, and use only what the files under "Read first" list.
|
|
66
|
+
|
|
67
|
+
### Breaking changes
|
|
68
|
+
|
|
69
|
+
#### Breaking: `@luz-ds/site` is now `@luz-ds/catalog`, the name the home and the docs already gave to level 3. Install `@luz-ds/catalog` and load `catalog.css` / `catalog.min.css` and `catalog.js` / `catalog.min.js` where you loaded the `site.*` files; its subpaths (`/search`, `/consent`, `/mode`, `/css`, `/css/min`, `/print.css`, `/components/*`, `/classes.json`, `/custom-elements.json`) keep their names. The cascade layer is `luz.catalog` instead of `luz.site`, in the order statement every stylesheet repeats (so tokens and core change too). The landing, cms, app and docs packages take `@luz-ds/catalog` as their optional peer. `luz-check` reads the new names and its `load/order` rule says tokens, core, catalog. The docs of the package are at `/docs/catalog/` (was `/docs/site/`). The tags (`<luz-search>`, `<luz-consent>`, `<luz-mode>`, `<luz-lang-switch>`, `<luz-submenu>`, `<luz-banner>`) and their classes do not change.
|
|
70
|
+
|
|
71
|
+
Older versions: https://github.com/nandovejer/luz/blob/main/packages/cms/CHANGELOG.md
|
|
72
|
+
|
|
73
|
+
### Read first
|
|
74
|
+
|
|
75
|
+
1. `dist/classes.json` in this package: the classes and custom properties its CSS defines. Write only those.
|
|
76
|
+
2. https://nandovejer.github.io/luz/llms.txt: the index of the documentation, short enough for a small context.
|
|
77
|
+
3. https://nandovejer.github.io/luz/llms-full.txt: the same pages in full.
|
|
78
|
+
4. https://nandovejer.github.io/luz/examples/: one standalone page of markup for each component and pattern.
|
|
79
|
+
|
|
80
|
+
### Load order
|
|
81
|
+
|
|
82
|
+
This package needs `@luz-ds/tokens` and `@luz-ds/core` loaded first.
|
|
83
|
+
|
|
84
|
+
`@luz-ds/catalog` is optional: the CSS of this package works with the packages above alone.
|
|
85
|
+
|
|
86
|
+
### Check what you write
|
|
87
|
+
|
|
88
|
+
Run `npx @luz-ds/check <files>` on every HTML and CSS file you write, and fix what it reports. To copy the accessibility reviewer into your project: `npx @luz-ds/check agent > .claude/agents/luz-accessibility-reviewer.md`.
|
|
89
|
+
|
|
90
|
+
<!-- luz:ai-agents:end -->
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"package": "@luz-ds/cms",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"classes": [
|
|
6
|
+
{ "name": "luz-cms-article", "kind": "pattern", "layer": "luz.cms", "files": ["components/article.css"], "defined": true, "block": "luz-cms-article" },
|
|
7
|
+
{ "name": "luz-cms-article-header", "kind": "pattern", "layer": "luz.cms", "files": ["components/article-header.css"], "defined": true, "block": "luz-cms-article-header" },
|
|
8
|
+
{ "name": "luz-cms-article-header__byline", "kind": "pattern", "layer": "luz.cms", "files": ["components/article-header.css"], "defined": true, "block": "luz-cms-article-header", "part": "byline" },
|
|
9
|
+
{ "name": "luz-cms-article-header__kicker", "kind": "pattern", "layer": "luz.cms", "files": ["components/article-header.css"], "defined": true, "block": "luz-cms-article-header", "part": "kicker" },
|
|
10
|
+
{ "name": "luz-cms-article-header__media", "kind": "pattern", "layer": "luz.cms", "files": ["components/article-header.css"], "defined": true, "block": "luz-cms-article-header", "part": "media" },
|
|
11
|
+
{ "name": "luz-cms-article-header__standfirst", "kind": "pattern", "layer": "luz.cms", "files": ["components/article-header.css"], "defined": true, "block": "luz-cms-article-header", "part": "standfirst" },
|
|
12
|
+
{ "name": "luz-cms-article-header__title", "kind": "pattern", "layer": "luz.cms", "files": ["components/article-header.css"], "defined": true, "block": "luz-cms-article-header", "part": "title" },
|
|
13
|
+
{ "name": "luz-cms-article__layout", "kind": "pattern", "layer": "luz.cms", "files": ["components/article.css"], "defined": true, "block": "luz-cms-article", "part": "layout" },
|
|
14
|
+
{ "name": "luz-cms-footer", "kind": "pattern", "layer": "luz.cms", "files": ["components/footer.css"], "defined": true, "block": "luz-cms-footer" },
|
|
15
|
+
{ "name": "luz-cms-header", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header" },
|
|
16
|
+
{ "name": "luz-cms-header--masthead", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header", "modifier": "masthead" },
|
|
17
|
+
{ "name": "luz-cms-header__actions", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header", "part": "actions" },
|
|
18
|
+
{ "name": "luz-cms-header__brand", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header", "part": "brand" },
|
|
19
|
+
{ "name": "luz-cms-header__date", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header", "part": "date" },
|
|
20
|
+
{ "name": "luz-cms-header__sections", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header", "part": "sections" },
|
|
21
|
+
{ "name": "luz-cms-header__top", "kind": "pattern", "layer": "luz.cms", "files": ["components/header.css"], "defined": true, "block": "luz-cms-header", "part": "top" },
|
|
22
|
+
{ "name": "luz-cms-page-header", "kind": "pattern", "layer": "luz.cms", "files": ["components/page-header.css"], "defined": true, "block": "luz-cms-page-header" },
|
|
23
|
+
{ "name": "luz-cms-page-header__lead", "kind": "pattern", "layer": "luz.cms", "files": ["components/page-header.css"], "defined": true, "block": "luz-cms-page-header", "part": "lead" },
|
|
24
|
+
{ "name": "luz-cms-page-header__title", "kind": "pattern", "layer": "luz.cms", "files": ["components/page-header.css"], "defined": true, "block": "luz-cms-page-header", "part": "title" },
|
|
25
|
+
{ "name": "luz-cms-toc", "kind": "pattern", "layer": "luz.cms", "files": ["components/article.css"], "defined": true, "block": "luz-cms-toc" },
|
|
26
|
+
{ "name": "luz-cms-toc__list", "kind": "pattern", "layer": "luz.cms", "files": ["components/article.css"], "defined": true, "block": "luz-cms-toc", "part": "list" },
|
|
27
|
+
{ "name": "luz-cms-toc__title", "kind": "pattern", "layer": "luz.cms", "files": ["components/article.css"], "defined": true, "block": "luz-cms-toc", "part": "title" },
|
|
28
|
+
{ "name": "o-row", "kind": "object", "layer": "luz.cms", "files": ["components/footer.css", "components/header.css"], "defined": false, "block": "o-row" },
|
|
29
|
+
{ "name": "o-sticky", "kind": "object", "layer": "luz.cms", "files": ["components/article.css"], "defined": false, "block": "o-sticky" }
|
|
30
|
+
],
|
|
31
|
+
"properties": [
|
|
32
|
+
{ "name": "--luz-cms-toc-top", "scope": "component", "layer": "luz.cms", "files": ["components/article.css"] },
|
|
33
|
+
{ "name": "--luz-lang-switch-top", "scope": "component", "layer": "luz.cms", "files": ["components/header.css"] }
|
|
34
|
+
]
|
|
35
|
+
}
|
package/dist/cms.css
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
@layer luz.tokens, luz.themes, luz.settings, luz.generic, luz.elements, luz.objects, luz.components, luz.utilities, luz.catalog, luz.landing, luz.cms, luz.app, luz.docs, luz.print;
|
|
2
|
+
@layer luz.cms {
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
LUZ CMS
|
|
5
|
+
The page structure of one kind of site, a blog, a newspaper or any CMS:
|
|
6
|
+
its header, page header, article header, article with its contents, and
|
|
7
|
+
footer. Each is a class of cms on a native element, laid out in the
|
|
8
|
+
markup by core's objects (.o-page, .o-sticky, .o-container, .o-row,
|
|
9
|
+
.o-stack). Any stack: the classes go on any element, so a template of
|
|
10
|
+
any CMS can emit them.
|
|
11
|
+
Requires: @luz-ds/tokens and @luz-ds/core loaded first; @luz-ds/catalog
|
|
12
|
+
optional, loaded before this file.
|
|
13
|
+
========================================================================== */
|
|
14
|
+
|
|
15
|
+
/* ==========================================================================
|
|
16
|
+
LUZ CMS: header.
|
|
17
|
+
The blog bar: header.luz-cms-header.o-sticky >
|
|
18
|
+
div.o-container.o-container--inline.o-row holding core's .luz-nav-toggle,
|
|
19
|
+
the __brand link, core's nav.luz-navbar[popover] and a div.o-row.__actions
|
|
20
|
+
(site's <luz-search>, then an optional <luz-lang-switch>). Core gives the
|
|
21
|
+
stickiness, the width, the row and the collapsing links; cms adds the
|
|
22
|
+
surface, the divider, the masthead brand and the gaps.
|
|
23
|
+
--masthead, the newspaper: three rows in an .o-stack (__top with the
|
|
24
|
+
__date and the __actions, the large centred __brand, and __sections with
|
|
25
|
+
the toggle and the navbar between two rules), not sticky.
|
|
26
|
+
========================================================================== */
|
|
27
|
+
|
|
28
|
+
/* A one-row bar of 44px controls is core's --luz-bar-h tall: two 2xs
|
|
29
|
+
paddings, the row and the divider. With enlarged text the row wraps
|
|
30
|
+
and the bar grows. */
|
|
31
|
+
.luz-cms-header {
|
|
32
|
+
padding-block: var(--luz-space-2xs);
|
|
33
|
+
border-block-end: 1px solid var(--luz-divider);
|
|
34
|
+
background: var(--luz-surface-page);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* The row wraps rather than overflow (WCAG 1.4.4, 1.4.10); its gutters are
|
|
38
|
+
the page's, so the brand starts where the content starts */
|
|
39
|
+
.luz-cms-header > .o-row {
|
|
40
|
+
gap: var(--luz-space-xs) var(--luz-space-md);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* The publication's name: a link, never a heading (the story's title is
|
|
44
|
+
the h1). It wraps, never ellipsised, and takes the free room of the row,
|
|
45
|
+
which pushes the links and the actions to the end */
|
|
46
|
+
.luz-cms-header__brand {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
min-block-size: var(--luz-control-lg);
|
|
50
|
+
margin-inline-end: auto;
|
|
51
|
+
color: var(--luz-text-primary);
|
|
52
|
+
font-family: var(--luz-font-heading);
|
|
53
|
+
font-size: var(--luz-text-xl);
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
text-decoration: none;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.luz-cms-header__brand:hover {
|
|
59
|
+
text-decoration: underline;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* A logo: an <img> whose alt is the publication's name */
|
|
63
|
+
.luz-cms-header__brand :where(img) {
|
|
64
|
+
block-size: var(--luz-control-lg);
|
|
65
|
+
inline-size: auto;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.luz-cms-header__actions {
|
|
69
|
+
gap: var(--luz-space-xs);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* The language list of site's <luz-lang-switch> opens under this bar */
|
|
73
|
+
.luz-cms-header :where(luz-lang-switch) {
|
|
74
|
+
--luz-lang-switch-top: var(--luz-bar-h);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* --masthead: room around three rows that scroll away with the page */
|
|
78
|
+
.luz-cms-header--masthead {
|
|
79
|
+
padding-block: var(--luz-space-md);
|
|
80
|
+
border-block-end: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* The date gives way to the search: it shrinks and wraps, the search keeps
|
|
84
|
+
its row */
|
|
85
|
+
.luz-cms-header__top {
|
|
86
|
+
flex-wrap: nowrap;
|
|
87
|
+
justify-content: space-between;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.luz-cms-header__date {
|
|
91
|
+
flex: 1 1 0;
|
|
92
|
+
min-inline-size: 0;
|
|
93
|
+
margin: 0;
|
|
94
|
+
color: var(--luz-text-secondary);
|
|
95
|
+
font-family: var(--luz-font-sans);
|
|
96
|
+
font-size: var(--luz-text-sm);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.luz-cms-header--masthead .luz-cms-header__brand {
|
|
100
|
+
display: block;
|
|
101
|
+
margin: 0;
|
|
102
|
+
font-size: var(--luz-text-4xl);
|
|
103
|
+
line-height: 1.1;
|
|
104
|
+
text-align: center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.luz-cms-header--masthead .luz-cms-header__brand :where(img) {
|
|
108
|
+
block-size: calc(var(--luz-control-lg) * 2);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* The rules keep clear of the menu button's border */
|
|
112
|
+
.luz-cms-header__sections {
|
|
113
|
+
padding-block: var(--luz-space-2xs);
|
|
114
|
+
border-block: 1px solid var(--luz-divider);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media (min-width: 769px) {
|
|
118
|
+
.luz-cms-header > .o-row {
|
|
119
|
+
column-gap: var(--luz-space-lg);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.luz-cms-header__sections {
|
|
123
|
+
justify-content: center;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* With the links in the panel, the brand fills the room between the toggle
|
|
128
|
+
and the actions and wraps there, so the bar stays one row of controls */
|
|
129
|
+
@media (max-width: 768px) {
|
|
130
|
+
.luz-cms-header > .o-row > .luz-cms-header__brand {
|
|
131
|
+
flex: 1 1 0;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@media (max-width: 1023px) {
|
|
136
|
+
.luz-cms-header--masthead .luz-cms-header__brand {
|
|
137
|
+
font-size: var(--luz-text-3xl);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@media (max-width: 640px) {
|
|
142
|
+
.luz-cms-header__brand {
|
|
143
|
+
font-size: var(--luz-text-lg);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.luz-cms-header--masthead .luz-cms-header__brand {
|
|
147
|
+
font-size: var(--luz-text-2xl);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/* With anchor positioning the panels opened inside the bar (core's navbar,
|
|
152
|
+
the language list) open at its block end, on two rows as on one; in the
|
|
153
|
+
masthead, the navbar's panel opens under the sections row. Scoped, so
|
|
154
|
+
with two bars on a page each panel finds its own */
|
|
155
|
+
@supports (anchor-name: --luz-bar) {
|
|
156
|
+
.luz-cms-header,
|
|
157
|
+
.luz-cms-header__sections {
|
|
158
|
+
anchor-name: --luz-bar;
|
|
159
|
+
anchor-scope: --luz-bar;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.luz-cms-header :where(luz-lang-switch) {
|
|
163
|
+
--luz-lang-switch-top: anchor(--luz-bar end, var(--luz-bar-h));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* ==========================================================================
|
|
168
|
+
LUZ CMS: page header.
|
|
169
|
+
The title of a page that is not an article (about, contact):
|
|
170
|
+
.luz-cms-page-header > h1.__title + p.__lead, the one sentence that says
|
|
171
|
+
what the page is for. An article has .luz-cms-article-header instead.
|
|
172
|
+
========================================================================== */
|
|
173
|
+
|
|
174
|
+
.luz-cms-page-header {
|
|
175
|
+
margin-block-end: var(--luz-space-xl);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.luz-cms-page-header__title {
|
|
179
|
+
margin-block-end: var(--luz-space-2xs);
|
|
180
|
+
color: var(--luz-text-primary);
|
|
181
|
+
font-family: var(--luz-font-heading);
|
|
182
|
+
font-size: var(--luz-text-3xl);
|
|
183
|
+
font-weight: 300;
|
|
184
|
+
letter-spacing: -1px;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.luz-cms-page-header__lead {
|
|
188
|
+
max-inline-size: 600px;
|
|
189
|
+
color: var(--luz-text-secondary);
|
|
190
|
+
font-size: var(--luz-text-base);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@media (max-width: 640px) {
|
|
194
|
+
.luz-cms-page-header__title {
|
|
195
|
+
font-size: var(--luz-text-2xl);
|
|
196
|
+
letter-spacing: -0.5px;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* Spacing between letters breaks the joins of Arabic script */
|
|
201
|
+
.luz-cms-page-header__title:lang(ar) {
|
|
202
|
+
letter-spacing: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* ==========================================================================
|
|
206
|
+
LUZ CMS: article header.
|
|
207
|
+
The top of a post or a story: its section, the title, the standfirst,
|
|
208
|
+
the byline and an optional lead picture. The classes go on any element,
|
|
209
|
+
so a template of any CMS can emit them (in WordPress, a block's
|
|
210
|
+
className); each part styles its text by inheritance, so a wrapper
|
|
211
|
+
around a paragraph works as well as the paragraph.
|
|
212
|
+
========================================================================== */
|
|
213
|
+
|
|
214
|
+
.luz-cms-article-header {
|
|
215
|
+
display: grid;
|
|
216
|
+
gap: var(--luz-space-sm);
|
|
217
|
+
margin-block-end: var(--luz-space-xl);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* The section above the title, in the voice of site's hero eyebrow, so a
|
|
221
|
+
story and a home page start alike. A link in it stays a link. */
|
|
222
|
+
.luz-cms-article-header__kicker {
|
|
223
|
+
font-family: var(--luz-font-mono);
|
|
224
|
+
font-size: var(--luz-text-xs);
|
|
225
|
+
font-weight: 500;
|
|
226
|
+
line-height: 1.5;
|
|
227
|
+
letter-spacing: 0.1em;
|
|
228
|
+
text-transform: uppercase;
|
|
229
|
+
color: var(--luz-text-secondary);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* The mono has no Arabic letters; spacing between letters breaks the joins */
|
|
233
|
+
.luz-cms-article-header__kicker:lang(ar) {
|
|
234
|
+
font-family: var(--luz-font-sans);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.luz-cms-article-header__kicker:lang(ar),
|
|
238
|
+
.luz-cms-article-header__title:lang(ar) {
|
|
239
|
+
letter-spacing: 0;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/* The title of a story runs long: balanced lines, a little tighter. The
|
|
243
|
+
heading's look is set here too, so a template that writes the title in
|
|
244
|
+
another element (a link in a <p>, a block's wrapper) keeps it. */
|
|
245
|
+
.luz-cms-article-header__title {
|
|
246
|
+
font-family: var(--luz-font-heading);
|
|
247
|
+
font-size: var(--luz-text-3xl);
|
|
248
|
+
font-weight: 300;
|
|
249
|
+
line-height: 1.15;
|
|
250
|
+
letter-spacing: -0.02em;
|
|
251
|
+
text-wrap: balance;
|
|
252
|
+
color: var(--luz-text-primary);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* The standfirst: what the story says, in a sentence or two */
|
|
256
|
+
.luz-cms-article-header__standfirst {
|
|
257
|
+
max-inline-size: 70ch;
|
|
258
|
+
font-size: var(--luz-text-lg);
|
|
259
|
+
line-height: 1.4;
|
|
260
|
+
text-wrap: pretty;
|
|
261
|
+
color: var(--luz-text-secondary);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* Who wrote it and when: an avatar, then its lines. Facts, not prose: the
|
|
265
|
+
sans, as navigation and labels are */
|
|
266
|
+
.luz-cms-article-header__byline {
|
|
267
|
+
display: flex;
|
|
268
|
+
flex-wrap: wrap;
|
|
269
|
+
align-items: center;
|
|
270
|
+
gap: var(--luz-space-xs) var(--luz-space-sm);
|
|
271
|
+
margin-block-start: var(--luz-space-xs);
|
|
272
|
+
font-family: var(--luz-font-sans);
|
|
273
|
+
font-size: var(--luz-text-md);
|
|
274
|
+
line-height: 1.5;
|
|
275
|
+
color: var(--luz-text-secondary);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* The lead picture and its caption, edge to edge: core's bare <figure> is
|
|
279
|
+
a tinted panel, which would frame the photo twice */
|
|
280
|
+
.luz-cms-article-header__media {
|
|
281
|
+
margin-block: var(--luz-space-sm) 0;
|
|
282
|
+
margin-inline: 0;
|
|
283
|
+
padding: 0;
|
|
284
|
+
background: none;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
@media (max-width: 640px) {
|
|
288
|
+
.luz-cms-article-header__title {
|
|
289
|
+
font-size: var(--luz-text-2xl);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.luz-cms-article-header__standfirst {
|
|
293
|
+
font-size: var(--luz-text-base);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* ==========================================================================
|
|
298
|
+
LUZ CMS: article and its table of contents.
|
|
299
|
+
.luz-cms-article is the room the story has (a size container). Its
|
|
300
|
+
__layout puts the contents beside the text, at the inline end, when that
|
|
301
|
+
room is 46rem or more, and above the text below that; beside it, the
|
|
302
|
+
contents stay in view while the text scrolls. The contents come first in
|
|
303
|
+
the source, so they are read and reached first in both layouts.
|
|
304
|
+
No JavaScript of its own: with data-luz-spy on the contents, core's
|
|
305
|
+
scroll spy (initSidebar, run by luz.js) marks the link of the section in
|
|
306
|
+
view with aria-current="true".
|
|
307
|
+
========================================================================== */
|
|
308
|
+
|
|
309
|
+
.luz-cms-article {
|
|
310
|
+
container-type: inline-size;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.luz-cms-article__layout {
|
|
314
|
+
display: grid;
|
|
315
|
+
grid-template-columns: minmax(0, 1fr);
|
|
316
|
+
gap: var(--luz-space-xl) var(--luz-space-2xl);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.luz-cms-toc__title {
|
|
320
|
+
margin-block-end: var(--luz-space-xs);
|
|
321
|
+
font-family: var(--luz-font-sans);
|
|
322
|
+
font-size: var(--luz-text-base);
|
|
323
|
+
font-weight: 600;
|
|
324
|
+
letter-spacing: 0;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/* A rule along the list; the current link draws its bar over it */
|
|
328
|
+
.luz-cms-toc__list {
|
|
329
|
+
list-style: none;
|
|
330
|
+
border-inline-start: 1px solid var(--luz-divider);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* One link a line, on the page's colours */
|
|
334
|
+
.luz-cms-toc__list a {
|
|
335
|
+
display: block;
|
|
336
|
+
margin-inline-start: -1px;
|
|
337
|
+
padding: var(--luz-space-2xs) var(--luz-space-sm);
|
|
338
|
+
border-inline-start: 2px solid transparent;
|
|
339
|
+
font-size: var(--luz-text-md);
|
|
340
|
+
color: var(--luz-text-secondary);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.luz-cms-toc__list a:hover {
|
|
344
|
+
background: var(--luz-surface-muted);
|
|
345
|
+
color: var(--luz-text-primary);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/* The section in view: a bar and the weight, never colour alone */
|
|
349
|
+
.luz-cms-toc__list a[aria-current="true"] {
|
|
350
|
+
border-inline-start-color: var(--luz-brand-primary);
|
|
351
|
+
color: var(--luz-text-primary);
|
|
352
|
+
font-weight: 600;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/* Beside the text: 13rem, as wide as the docs' "On this page" rail, which
|
|
356
|
+
keeps 30rem or more for the text. A list longer than the window scrolls
|
|
357
|
+
inside the contents. */
|
|
358
|
+
@container (min-width: 46rem) {
|
|
359
|
+
.luz-cms-article__layout {
|
|
360
|
+
grid-template-columns: minmax(0, 1fr) 13rem;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.luz-cms-toc {
|
|
364
|
+
position: sticky;
|
|
365
|
+
inset-block-start: var(--luz-cms-toc-top, var(--luz-space-lg));
|
|
366
|
+
grid-column: 2;
|
|
367
|
+
grid-row: 1;
|
|
368
|
+
align-self: start;
|
|
369
|
+
max-block-size: calc(100dvh - var(--luz-cms-toc-top, var(--luz-space-lg)) - var(--luz-space-lg));
|
|
370
|
+
overflow-y: auto;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* Under a sticky bar (core's .o-sticky, one row of --luz-bar-h), where it
|
|
375
|
+
sticks (the same query) */
|
|
376
|
+
@media (min-height: 30rem) {
|
|
377
|
+
:root:has(.o-sticky) .luz-cms-toc {
|
|
378
|
+
--luz-cms-toc-top: calc(var(--luz-bar-h) + var(--luz-space-lg));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/* ==========================================================================
|
|
383
|
+
LUZ CMS: footer.
|
|
384
|
+
footer.luz-cms-footer > div.o-container.o-container--inline.o-row: a
|
|
385
|
+
divider above, its items at the two ends of the row; at 768px and below
|
|
386
|
+
a column aligned to the start.
|
|
387
|
+
========================================================================== */
|
|
388
|
+
|
|
389
|
+
.luz-cms-footer {
|
|
390
|
+
padding-block: var(--luz-space-lg) var(--luz-space-xl);
|
|
391
|
+
border-block-start: 1px solid var(--luz-divider);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.luz-cms-footer > .o-row {
|
|
395
|
+
justify-content: space-between;
|
|
396
|
+
gap: var(--luz-space-md);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/* A column that does not wrap: a wrapping column nested in grids makes
|
|
400
|
+
Chromium's layout take tens of seconds */
|
|
401
|
+
@media (max-width: 768px) {
|
|
402
|
+
.luz-cms-footer > .o-row {
|
|
403
|
+
flex-flow: column nowrap;
|
|
404
|
+
align-items: flex-start;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
}
|
package/dist/cms.min.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer luz.tokens,luz.themes,luz.settings,luz.generic,luz.elements,luz.objects,luz.components,luz.utilities,luz.catalog,luz.landing,luz.cms,luz.app,luz.docs,luz.print;@layer luz.cms{.luz-cms-header{padding-block:var(--luz-space-2xs);border-block-end:1px solid var(--luz-divider);background:var(--luz-surface-page)}.luz-cms-header>.o-row{gap:var(--luz-space-xs) var(--luz-space-md)}.luz-cms-header__brand{display:inline-flex;align-items:center;min-block-size:var(--luz-control-lg);margin-inline-end:auto;color:var(--luz-text-primary);font-family:var(--luz-font-heading);font-size:var(--luz-text-xl);font-weight:600;text-decoration:none}.luz-cms-header__brand:hover{text-decoration:underline}.luz-cms-header__brand :where(img){block-size:var(--luz-control-lg);inline-size:auto}.luz-cms-header__actions{gap:var(--luz-space-xs)}.luz-cms-header :where(luz-lang-switch){--luz-lang-switch-top: var(--luz-bar-h)}.luz-cms-header--masthead{padding-block:var(--luz-space-md);border-block-end:0}.luz-cms-header__top{flex-wrap:nowrap;justify-content:space-between}.luz-cms-header__date{flex:1 1 0;min-inline-size:0;margin:0;color:var(--luz-text-secondary);font-family:var(--luz-font-sans);font-size:var(--luz-text-sm)}.luz-cms-header--masthead .luz-cms-header__brand{display:block;margin:0;font-size:var(--luz-text-4xl);line-height:1.1;text-align:center}.luz-cms-header--masthead .luz-cms-header__brand :where(img){block-size:calc(var(--luz-control-lg) * 2)}.luz-cms-header__sections{padding-block:var(--luz-space-2xs);border-block:1px solid var(--luz-divider)}@media(min-width:769px){.luz-cms-header>.o-row{column-gap:var(--luz-space-lg)}.luz-cms-header__sections{justify-content:center}}@media(max-width:768px){.luz-cms-header>.o-row>.luz-cms-header__brand{flex:1 1 0}}@media(max-width:1023px){.luz-cms-header--masthead .luz-cms-header__brand{font-size:var(--luz-text-3xl)}}@media(max-width:640px){.luz-cms-header__brand{font-size:var(--luz-text-lg)}.luz-cms-header--masthead .luz-cms-header__brand{font-size:var(--luz-text-2xl)}}@supports (anchor-name: --luz-bar){.luz-cms-header,.luz-cms-header__sections{anchor-name:--luz-bar;anchor-scope:--luz-bar}.luz-cms-header :where(luz-lang-switch){--luz-lang-switch-top: anchor(--luz-bar end, var(--luz-bar-h))}}.luz-cms-page-header{margin-block-end:var(--luz-space-xl)}.luz-cms-page-header__title{margin-block-end:var(--luz-space-2xs);color:var(--luz-text-primary);font-family:var(--luz-font-heading);font-size:var(--luz-text-3xl);font-weight:300;letter-spacing:-1px}.luz-cms-page-header__lead{max-inline-size:600px;color:var(--luz-text-secondary);font-size:var(--luz-text-base)}@media(max-width:640px){.luz-cms-page-header__title{font-size:var(--luz-text-2xl);letter-spacing:-.5px}}.luz-cms-page-header__title:lang(ar){letter-spacing:0}.luz-cms-article-header{display:grid;gap:var(--luz-space-sm);margin-block-end:var(--luz-space-xl)}.luz-cms-article-header__kicker{font-family:var(--luz-font-mono);font-size:var(--luz-text-xs);font-weight:500;line-height:1.5;letter-spacing:.1em;text-transform:uppercase;color:var(--luz-text-secondary)}.luz-cms-article-header__kicker:lang(ar){font-family:var(--luz-font-sans)}.luz-cms-article-header__kicker:lang(ar),.luz-cms-article-header__title:lang(ar){letter-spacing:0}.luz-cms-article-header__title{font-family:var(--luz-font-heading);font-size:var(--luz-text-3xl);font-weight:300;line-height:1.15;letter-spacing:-.02em;text-wrap:balance;color:var(--luz-text-primary)}.luz-cms-article-header__standfirst{max-inline-size:70ch;font-size:var(--luz-text-lg);line-height:1.4;text-wrap:pretty;color:var(--luz-text-secondary)}.luz-cms-article-header__byline{display:flex;flex-wrap:wrap;align-items:center;gap:var(--luz-space-xs) var(--luz-space-sm);margin-block-start:var(--luz-space-xs);font-family:var(--luz-font-sans);font-size:var(--luz-text-md);line-height:1.5;color:var(--luz-text-secondary)}.luz-cms-article-header__media{margin-block:var(--luz-space-sm) 0;margin-inline:0;padding:0;background:none}@media(max-width:640px){.luz-cms-article-header__title{font-size:var(--luz-text-2xl)}.luz-cms-article-header__standfirst{font-size:var(--luz-text-base)}}.luz-cms-article{container-type:inline-size}.luz-cms-article__layout{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--luz-space-xl) var(--luz-space-2xl)}.luz-cms-toc__title{margin-block-end:var(--luz-space-xs);font-family:var(--luz-font-sans);font-size:var(--luz-text-base);font-weight:600;letter-spacing:0}.luz-cms-toc__list{list-style:none;border-inline-start:1px solid var(--luz-divider)}.luz-cms-toc__list a{display:block;margin-inline-start:-1px;padding:var(--luz-space-2xs) var(--luz-space-sm);border-inline-start:2px solid transparent;font-size:var(--luz-text-md);color:var(--luz-text-secondary)}.luz-cms-toc__list a:hover{background:var(--luz-surface-muted);color:var(--luz-text-primary)}.luz-cms-toc__list a[aria-current=true]{border-inline-start-color:var(--luz-brand-primary);color:var(--luz-text-primary);font-weight:600}@container (min-width: 46rem){.luz-cms-article__layout{grid-template-columns:minmax(0,1fr) 13rem}.luz-cms-toc{position:sticky;inset-block-start:var(--luz-cms-toc-top, var(--luz-space-lg));grid-column:2;grid-row:1;align-self:start;max-block-size:calc(100dvh - var(--luz-cms-toc-top, var(--luz-space-lg)) - var(--luz-space-lg));overflow-y:auto}}@media(min-height:30rem){:root:has(.o-sticky) .luz-cms-toc{--luz-cms-toc-top: calc(var(--luz-bar-h) + var(--luz-space-lg))}}.luz-cms-footer{padding-block:var(--luz-space-lg) var(--luz-space-xl);border-block-start:1px solid var(--luz-divider)}.luz-cms-footer>.o-row{justify-content:space-between;gap:var(--luz-space-md)}@media(max-width:768px){.luz-cms-footer>.o-row{flex-flow:column nowrap;align-items:flex-start}}}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
@layer luz.tokens, luz.themes, luz.settings, luz.generic, luz.elements, luz.objects, luz.components, luz.utilities, luz.catalog, luz.landing, luz.cms, luz.app, luz.docs, luz.print;
|
|
2
|
+
@layer luz.cms {
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
LUZ CMS: article header.
|
|
5
|
+
The top of a post or a story: its section, the title, the standfirst,
|
|
6
|
+
the byline and an optional lead picture. The classes go on any element,
|
|
7
|
+
so a template of any CMS can emit them (in WordPress, a block's
|
|
8
|
+
className); each part styles its text by inheritance, so a wrapper
|
|
9
|
+
around a paragraph works as well as the paragraph.
|
|
10
|
+
========================================================================== */
|
|
11
|
+
|
|
12
|
+
.luz-cms-article-header {
|
|
13
|
+
display: grid;
|
|
14
|
+
gap: var(--luz-space-sm);
|
|
15
|
+
margin-block-end: var(--luz-space-xl);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* The section above the title, in the voice of site's hero eyebrow, so a
|
|
19
|
+
story and a home page start alike. A link in it stays a link. */
|
|
20
|
+
.luz-cms-article-header__kicker {
|
|
21
|
+
font-family: var(--luz-font-mono);
|
|
22
|
+
font-size: var(--luz-text-xs);
|
|
23
|
+
font-weight: 500;
|
|
24
|
+
line-height: 1.5;
|
|
25
|
+
letter-spacing: 0.1em;
|
|
26
|
+
text-transform: uppercase;
|
|
27
|
+
color: var(--luz-text-secondary);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* The mono has no Arabic letters; spacing between letters breaks the joins */
|
|
31
|
+
.luz-cms-article-header__kicker:lang(ar) {
|
|
32
|
+
font-family: var(--luz-font-sans);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.luz-cms-article-header__kicker:lang(ar),
|
|
36
|
+
.luz-cms-article-header__title:lang(ar) {
|
|
37
|
+
letter-spacing: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* The title of a story runs long: balanced lines, a little tighter. The
|
|
41
|
+
heading's look is set here too, so a template that writes the title in
|
|
42
|
+
another element (a link in a <p>, a block's wrapper) keeps it. */
|
|
43
|
+
.luz-cms-article-header__title {
|
|
44
|
+
font-family: var(--luz-font-heading);
|
|
45
|
+
font-size: var(--luz-text-3xl);
|
|
46
|
+
font-weight: 300;
|
|
47
|
+
line-height: 1.15;
|
|
48
|
+
letter-spacing: -0.02em;
|
|
49
|
+
text-wrap: balance;
|
|
50
|
+
color: var(--luz-text-primary);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* The standfirst: what the story says, in a sentence or two */
|
|
54
|
+
.luz-cms-article-header__standfirst {
|
|
55
|
+
max-inline-size: 70ch;
|
|
56
|
+
font-size: var(--luz-text-lg);
|
|
57
|
+
line-height: 1.4;
|
|
58
|
+
text-wrap: pretty;
|
|
59
|
+
color: var(--luz-text-secondary);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Who wrote it and when: an avatar, then its lines. Facts, not prose: the
|
|
63
|
+
sans, as navigation and labels are */
|
|
64
|
+
.luz-cms-article-header__byline {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-wrap: wrap;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: var(--luz-space-xs) var(--luz-space-sm);
|
|
69
|
+
margin-block-start: var(--luz-space-xs);
|
|
70
|
+
font-family: var(--luz-font-sans);
|
|
71
|
+
font-size: var(--luz-text-md);
|
|
72
|
+
line-height: 1.5;
|
|
73
|
+
color: var(--luz-text-secondary);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* The lead picture and its caption, edge to edge: core's bare <figure> is
|
|
77
|
+
a tinted panel, which would frame the photo twice */
|
|
78
|
+
.luz-cms-article-header__media {
|
|
79
|
+
margin-block: var(--luz-space-sm) 0;
|
|
80
|
+
margin-inline: 0;
|
|
81
|
+
padding: 0;
|
|
82
|
+
background: none;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@media (max-width: 640px) {
|
|
86
|
+
.luz-cms-article-header__title {
|
|
87
|
+
font-size: var(--luz-text-2xl);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.luz-cms-article-header__standfirst {
|
|
91
|
+
font-size: var(--luz-text-base);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer luz.tokens,luz.themes,luz.settings,luz.generic,luz.elements,luz.objects,luz.components,luz.utilities,luz.catalog,luz.landing,luz.cms,luz.app,luz.docs,luz.print;@layer luz.cms{.luz-cms-article-header{display:grid;gap:var(--luz-space-sm);margin-block-end:var(--luz-space-xl)}.luz-cms-article-header__kicker{font-family:var(--luz-font-mono);font-size:var(--luz-text-xs);font-weight:500;line-height:1.5;letter-spacing:.1em;text-transform:uppercase;color:var(--luz-text-secondary)}.luz-cms-article-header__kicker:lang(ar){font-family:var(--luz-font-sans)}.luz-cms-article-header__kicker:lang(ar),.luz-cms-article-header__title:lang(ar){letter-spacing:0}.luz-cms-article-header__title{font-family:var(--luz-font-heading);font-size:var(--luz-text-3xl);font-weight:300;line-height:1.15;letter-spacing:-.02em;text-wrap:balance;color:var(--luz-text-primary)}.luz-cms-article-header__standfirst{max-inline-size:70ch;font-size:var(--luz-text-lg);line-height:1.4;text-wrap:pretty;color:var(--luz-text-secondary)}.luz-cms-article-header__byline{display:flex;flex-wrap:wrap;align-items:center;gap:var(--luz-space-xs) var(--luz-space-sm);margin-block-start:var(--luz-space-xs);font-family:var(--luz-font-sans);font-size:var(--luz-text-md);line-height:1.5;color:var(--luz-text-secondary)}.luz-cms-article-header__media{margin-block:var(--luz-space-sm) 0;margin-inline:0;padding:0;background:none}@media(max-width:640px){.luz-cms-article-header__title{font-size:var(--luz-text-2xl)}.luz-cms-article-header__standfirst{font-size:var(--luz-text-base)}}}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
@layer luz.tokens, luz.themes, luz.settings, luz.generic, luz.elements, luz.objects, luz.components, luz.utilities, luz.catalog, luz.landing, luz.cms, luz.app, luz.docs, luz.print;
|
|
2
|
+
@layer luz.cms {
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
LUZ CMS: article and its table of contents.
|
|
5
|
+
.luz-cms-article is the room the story has (a size container). Its
|
|
6
|
+
__layout puts the contents beside the text, at the inline end, when that
|
|
7
|
+
room is 46rem or more, and above the text below that; beside it, the
|
|
8
|
+
contents stay in view while the text scrolls. The contents come first in
|
|
9
|
+
the source, so they are read and reached first in both layouts.
|
|
10
|
+
No JavaScript of its own: with data-luz-spy on the contents, core's
|
|
11
|
+
scroll spy (initSidebar, run by luz.js) marks the link of the section in
|
|
12
|
+
view with aria-current="true".
|
|
13
|
+
========================================================================== */
|
|
14
|
+
|
|
15
|
+
.luz-cms-article {
|
|
16
|
+
container-type: inline-size;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.luz-cms-article__layout {
|
|
20
|
+
display: grid;
|
|
21
|
+
grid-template-columns: minmax(0, 1fr);
|
|
22
|
+
gap: var(--luz-space-xl) var(--luz-space-2xl);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.luz-cms-toc__title {
|
|
26
|
+
margin-block-end: var(--luz-space-xs);
|
|
27
|
+
font-family: var(--luz-font-sans);
|
|
28
|
+
font-size: var(--luz-text-base);
|
|
29
|
+
font-weight: 600;
|
|
30
|
+
letter-spacing: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* A rule along the list; the current link draws its bar over it */
|
|
34
|
+
.luz-cms-toc__list {
|
|
35
|
+
list-style: none;
|
|
36
|
+
border-inline-start: 1px solid var(--luz-divider);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* One link a line, on the page's colours */
|
|
40
|
+
.luz-cms-toc__list a {
|
|
41
|
+
display: block;
|
|
42
|
+
margin-inline-start: -1px;
|
|
43
|
+
padding: var(--luz-space-2xs) var(--luz-space-sm);
|
|
44
|
+
border-inline-start: 2px solid transparent;
|
|
45
|
+
font-size: var(--luz-text-md);
|
|
46
|
+
color: var(--luz-text-secondary);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.luz-cms-toc__list a:hover {
|
|
50
|
+
background: var(--luz-surface-muted);
|
|
51
|
+
color: var(--luz-text-primary);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* The section in view: a bar and the weight, never colour alone */
|
|
55
|
+
.luz-cms-toc__list a[aria-current="true"] {
|
|
56
|
+
border-inline-start-color: var(--luz-brand-primary);
|
|
57
|
+
color: var(--luz-text-primary);
|
|
58
|
+
font-weight: 600;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Beside the text: 13rem, as wide as the docs' "On this page" rail, which
|
|
62
|
+
keeps 30rem or more for the text. A list longer than the window scrolls
|
|
63
|
+
inside the contents. */
|
|
64
|
+
@container (min-width: 46rem) {
|
|
65
|
+
.luz-cms-article__layout {
|
|
66
|
+
grid-template-columns: minmax(0, 1fr) 13rem;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.luz-cms-toc {
|
|
70
|
+
position: sticky;
|
|
71
|
+
inset-block-start: var(--luz-cms-toc-top, var(--luz-space-lg));
|
|
72
|
+
grid-column: 2;
|
|
73
|
+
grid-row: 1;
|
|
74
|
+
align-self: start;
|
|
75
|
+
max-block-size: calc(100dvh - var(--luz-cms-toc-top, var(--luz-space-lg)) - var(--luz-space-lg));
|
|
76
|
+
overflow-y: auto;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Under a sticky bar (core's .o-sticky, one row of --luz-bar-h), where it
|
|
81
|
+
sticks (the same query) */
|
|
82
|
+
@media (min-height: 30rem) {
|
|
83
|
+
:root:has(.o-sticky) .luz-cms-toc {
|
|
84
|
+
--luz-cms-toc-top: calc(var(--luz-bar-h) + var(--luz-space-lg));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer luz.tokens,luz.themes,luz.settings,luz.generic,luz.elements,luz.objects,luz.components,luz.utilities,luz.catalog,luz.landing,luz.cms,luz.app,luz.docs,luz.print;@layer luz.cms{.luz-cms-article{container-type:inline-size}.luz-cms-article__layout{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--luz-space-xl) var(--luz-space-2xl)}.luz-cms-toc__title{margin-block-end:var(--luz-space-xs);font-family:var(--luz-font-sans);font-size:var(--luz-text-base);font-weight:600;letter-spacing:0}.luz-cms-toc__list{list-style:none;border-inline-start:1px solid var(--luz-divider)}.luz-cms-toc__list a{display:block;margin-inline-start:-1px;padding:var(--luz-space-2xs) var(--luz-space-sm);border-inline-start:2px solid transparent;font-size:var(--luz-text-md);color:var(--luz-text-secondary)}.luz-cms-toc__list a:hover{background:var(--luz-surface-muted);color:var(--luz-text-primary)}.luz-cms-toc__list a[aria-current=true]{border-inline-start-color:var(--luz-brand-primary);color:var(--luz-text-primary);font-weight:600}@container (min-width: 46rem){.luz-cms-article__layout{grid-template-columns:minmax(0,1fr) 13rem}.luz-cms-toc{position:sticky;inset-block-start:var(--luz-cms-toc-top, var(--luz-space-lg));grid-column:2;grid-row:1;align-self:start;max-block-size:calc(100dvh - var(--luz-cms-toc-top, var(--luz-space-lg)) - var(--luz-space-lg));overflow-y:auto}}@media(min-height:30rem){:root:has(.o-sticky) .luz-cms-toc{--luz-cms-toc-top: calc(var(--luz-bar-h) + var(--luz-space-lg))}}}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
@layer luz.tokens, luz.themes, luz.settings, luz.generic, luz.elements, luz.objects, luz.components, luz.utilities, luz.catalog, luz.landing, luz.cms, luz.app, luz.docs, luz.print;
|
|
2
|
+
@layer luz.cms {
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
LUZ CMS: footer.
|
|
5
|
+
footer.luz-cms-footer > div.o-container.o-container--inline.o-row: a
|
|
6
|
+
divider above, its items at the two ends of the row; at 768px and below
|
|
7
|
+
a column aligned to the start.
|
|
8
|
+
========================================================================== */
|
|
9
|
+
|
|
10
|
+
.luz-cms-footer {
|
|
11
|
+
padding-block: var(--luz-space-lg) var(--luz-space-xl);
|
|
12
|
+
border-block-start: 1px solid var(--luz-divider);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.luz-cms-footer > .o-row {
|
|
16
|
+
justify-content: space-between;
|
|
17
|
+
gap: var(--luz-space-md);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* A column that does not wrap: a wrapping column nested in grids makes
|
|
21
|
+
Chromium's layout take tens of seconds */
|
|
22
|
+
@media (max-width: 768px) {
|
|
23
|
+
.luz-cms-footer > .o-row {
|
|
24
|
+
flex-flow: column nowrap;
|
|
25
|
+
align-items: flex-start;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer luz.tokens,luz.themes,luz.settings,luz.generic,luz.elements,luz.objects,luz.components,luz.utilities,luz.catalog,luz.landing,luz.cms,luz.app,luz.docs,luz.print;@layer luz.cms{.luz-cms-footer{padding-block:var(--luz-space-lg) var(--luz-space-xl);border-block-start:1px solid var(--luz-divider)}.luz-cms-footer>.o-row{justify-content:space-between;gap:var(--luz-space-md)}@media(max-width:768px){.luz-cms-footer>.o-row{flex-flow:column nowrap;align-items:flex-start}}}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
@layer luz.tokens, luz.themes, luz.settings, luz.generic, luz.elements, luz.objects, luz.components, luz.utilities, luz.catalog, luz.landing, luz.cms, luz.app, luz.docs, luz.print;
|
|
2
|
+
@layer luz.cms {
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
LUZ CMS: header.
|
|
5
|
+
The blog bar: header.luz-cms-header.o-sticky >
|
|
6
|
+
div.o-container.o-container--inline.o-row holding core's .luz-nav-toggle,
|
|
7
|
+
the __brand link, core's nav.luz-navbar[popover] and a div.o-row.__actions
|
|
8
|
+
(site's <luz-search>, then an optional <luz-lang-switch>). Core gives the
|
|
9
|
+
stickiness, the width, the row and the collapsing links; cms adds the
|
|
10
|
+
surface, the divider, the masthead brand and the gaps.
|
|
11
|
+
--masthead, the newspaper: three rows in an .o-stack (__top with the
|
|
12
|
+
__date and the __actions, the large centred __brand, and __sections with
|
|
13
|
+
the toggle and the navbar between two rules), not sticky.
|
|
14
|
+
========================================================================== */
|
|
15
|
+
|
|
16
|
+
/* A one-row bar of 44px controls is core's --luz-bar-h tall: two 2xs
|
|
17
|
+
paddings, the row and the divider. With enlarged text the row wraps
|
|
18
|
+
and the bar grows. */
|
|
19
|
+
.luz-cms-header {
|
|
20
|
+
padding-block: var(--luz-space-2xs);
|
|
21
|
+
border-block-end: 1px solid var(--luz-divider);
|
|
22
|
+
background: var(--luz-surface-page);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* The row wraps rather than overflow (WCAG 1.4.4, 1.4.10); its gutters are
|
|
26
|
+
the page's, so the brand starts where the content starts */
|
|
27
|
+
.luz-cms-header > .o-row {
|
|
28
|
+
gap: var(--luz-space-xs) var(--luz-space-md);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* The publication's name: a link, never a heading (the story's title is
|
|
32
|
+
the h1). It wraps, never ellipsised, and takes the free room of the row,
|
|
33
|
+
which pushes the links and the actions to the end */
|
|
34
|
+
.luz-cms-header__brand {
|
|
35
|
+
display: inline-flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
min-block-size: var(--luz-control-lg);
|
|
38
|
+
margin-inline-end: auto;
|
|
39
|
+
color: var(--luz-text-primary);
|
|
40
|
+
font-family: var(--luz-font-heading);
|
|
41
|
+
font-size: var(--luz-text-xl);
|
|
42
|
+
font-weight: 600;
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.luz-cms-header__brand:hover {
|
|
47
|
+
text-decoration: underline;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* A logo: an <img> whose alt is the publication's name */
|
|
51
|
+
.luz-cms-header__brand :where(img) {
|
|
52
|
+
block-size: var(--luz-control-lg);
|
|
53
|
+
inline-size: auto;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.luz-cms-header__actions {
|
|
57
|
+
gap: var(--luz-space-xs);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* The language list of site's <luz-lang-switch> opens under this bar */
|
|
61
|
+
.luz-cms-header :where(luz-lang-switch) {
|
|
62
|
+
--luz-lang-switch-top: var(--luz-bar-h);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* --masthead: room around three rows that scroll away with the page */
|
|
66
|
+
.luz-cms-header--masthead {
|
|
67
|
+
padding-block: var(--luz-space-md);
|
|
68
|
+
border-block-end: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* The date gives way to the search: it shrinks and wraps, the search keeps
|
|
72
|
+
its row */
|
|
73
|
+
.luz-cms-header__top {
|
|
74
|
+
flex-wrap: nowrap;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.luz-cms-header__date {
|
|
79
|
+
flex: 1 1 0;
|
|
80
|
+
min-inline-size: 0;
|
|
81
|
+
margin: 0;
|
|
82
|
+
color: var(--luz-text-secondary);
|
|
83
|
+
font-family: var(--luz-font-sans);
|
|
84
|
+
font-size: var(--luz-text-sm);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.luz-cms-header--masthead .luz-cms-header__brand {
|
|
88
|
+
display: block;
|
|
89
|
+
margin: 0;
|
|
90
|
+
font-size: var(--luz-text-4xl);
|
|
91
|
+
line-height: 1.1;
|
|
92
|
+
text-align: center;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.luz-cms-header--masthead .luz-cms-header__brand :where(img) {
|
|
96
|
+
block-size: calc(var(--luz-control-lg) * 2);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* The rules keep clear of the menu button's border */
|
|
100
|
+
.luz-cms-header__sections {
|
|
101
|
+
padding-block: var(--luz-space-2xs);
|
|
102
|
+
border-block: 1px solid var(--luz-divider);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@media (min-width: 769px) {
|
|
106
|
+
.luz-cms-header > .o-row {
|
|
107
|
+
column-gap: var(--luz-space-lg);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.luz-cms-header__sections {
|
|
111
|
+
justify-content: center;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* With the links in the panel, the brand fills the room between the toggle
|
|
116
|
+
and the actions and wraps there, so the bar stays one row of controls */
|
|
117
|
+
@media (max-width: 768px) {
|
|
118
|
+
.luz-cms-header > .o-row > .luz-cms-header__brand {
|
|
119
|
+
flex: 1 1 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@media (max-width: 1023px) {
|
|
124
|
+
.luz-cms-header--masthead .luz-cms-header__brand {
|
|
125
|
+
font-size: var(--luz-text-3xl);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@media (max-width: 640px) {
|
|
130
|
+
.luz-cms-header__brand {
|
|
131
|
+
font-size: var(--luz-text-lg);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.luz-cms-header--masthead .luz-cms-header__brand {
|
|
135
|
+
font-size: var(--luz-text-2xl);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* With anchor positioning the panels opened inside the bar (core's navbar,
|
|
140
|
+
the language list) open at its block end, on two rows as on one; in the
|
|
141
|
+
masthead, the navbar's panel opens under the sections row. Scoped, so
|
|
142
|
+
with two bars on a page each panel finds its own */
|
|
143
|
+
@supports (anchor-name: --luz-bar) {
|
|
144
|
+
.luz-cms-header,
|
|
145
|
+
.luz-cms-header__sections {
|
|
146
|
+
anchor-name: --luz-bar;
|
|
147
|
+
anchor-scope: --luz-bar;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.luz-cms-header :where(luz-lang-switch) {
|
|
151
|
+
--luz-lang-switch-top: anchor(--luz-bar end, var(--luz-bar-h));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer luz.tokens,luz.themes,luz.settings,luz.generic,luz.elements,luz.objects,luz.components,luz.utilities,luz.catalog,luz.landing,luz.cms,luz.app,luz.docs,luz.print;@layer luz.cms{.luz-cms-header{padding-block:var(--luz-space-2xs);border-block-end:1px solid var(--luz-divider);background:var(--luz-surface-page)}.luz-cms-header>.o-row{gap:var(--luz-space-xs) var(--luz-space-md)}.luz-cms-header__brand{display:inline-flex;align-items:center;min-block-size:var(--luz-control-lg);margin-inline-end:auto;color:var(--luz-text-primary);font-family:var(--luz-font-heading);font-size:var(--luz-text-xl);font-weight:600;text-decoration:none}.luz-cms-header__brand:hover{text-decoration:underline}.luz-cms-header__brand :where(img){block-size:var(--luz-control-lg);inline-size:auto}.luz-cms-header__actions{gap:var(--luz-space-xs)}.luz-cms-header :where(luz-lang-switch){--luz-lang-switch-top: var(--luz-bar-h)}.luz-cms-header--masthead{padding-block:var(--luz-space-md);border-block-end:0}.luz-cms-header__top{flex-wrap:nowrap;justify-content:space-between}.luz-cms-header__date{flex:1 1 0;min-inline-size:0;margin:0;color:var(--luz-text-secondary);font-family:var(--luz-font-sans);font-size:var(--luz-text-sm)}.luz-cms-header--masthead .luz-cms-header__brand{display:block;margin:0;font-size:var(--luz-text-4xl);line-height:1.1;text-align:center}.luz-cms-header--masthead .luz-cms-header__brand :where(img){block-size:calc(var(--luz-control-lg) * 2)}.luz-cms-header__sections{padding-block:var(--luz-space-2xs);border-block:1px solid var(--luz-divider)}@media(min-width:769px){.luz-cms-header>.o-row{column-gap:var(--luz-space-lg)}.luz-cms-header__sections{justify-content:center}}@media(max-width:768px){.luz-cms-header>.o-row>.luz-cms-header__brand{flex:1 1 0}}@media(max-width:1023px){.luz-cms-header--masthead .luz-cms-header__brand{font-size:var(--luz-text-3xl)}}@media(max-width:640px){.luz-cms-header__brand{font-size:var(--luz-text-lg)}.luz-cms-header--masthead .luz-cms-header__brand{font-size:var(--luz-text-2xl)}}@supports (anchor-name: --luz-bar){.luz-cms-header,.luz-cms-header__sections{anchor-name:--luz-bar;anchor-scope:--luz-bar}.luz-cms-header :where(luz-lang-switch){--luz-lang-switch-top: anchor(--luz-bar end, var(--luz-bar-h))}}}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@layer luz.tokens, luz.themes, luz.settings, luz.generic, luz.elements, luz.objects, luz.components, luz.utilities, luz.catalog, luz.landing, luz.cms, luz.app, luz.docs, luz.print;
|
|
2
|
+
@layer luz.cms {
|
|
3
|
+
/* ==========================================================================
|
|
4
|
+
LUZ CMS: page header.
|
|
5
|
+
The title of a page that is not an article (about, contact):
|
|
6
|
+
.luz-cms-page-header > h1.__title + p.__lead, the one sentence that says
|
|
7
|
+
what the page is for. An article has .luz-cms-article-header instead.
|
|
8
|
+
========================================================================== */
|
|
9
|
+
|
|
10
|
+
.luz-cms-page-header {
|
|
11
|
+
margin-block-end: var(--luz-space-xl);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.luz-cms-page-header__title {
|
|
15
|
+
margin-block-end: var(--luz-space-2xs);
|
|
16
|
+
color: var(--luz-text-primary);
|
|
17
|
+
font-family: var(--luz-font-heading);
|
|
18
|
+
font-size: var(--luz-text-3xl);
|
|
19
|
+
font-weight: 300;
|
|
20
|
+
letter-spacing: -1px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.luz-cms-page-header__lead {
|
|
24
|
+
max-inline-size: 600px;
|
|
25
|
+
color: var(--luz-text-secondary);
|
|
26
|
+
font-size: var(--luz-text-base);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@media (max-width: 640px) {
|
|
30
|
+
.luz-cms-page-header__title {
|
|
31
|
+
font-size: var(--luz-text-2xl);
|
|
32
|
+
letter-spacing: -0.5px;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Spacing between letters breaks the joins of Arabic script */
|
|
37
|
+
.luz-cms-page-header__title:lang(ar) {
|
|
38
|
+
letter-spacing: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer luz.tokens,luz.themes,luz.settings,luz.generic,luz.elements,luz.objects,luz.components,luz.utilities,luz.catalog,luz.landing,luz.cms,luz.app,luz.docs,luz.print;@layer luz.cms{.luz-cms-page-header{margin-block-end:var(--luz-space-xl)}.luz-cms-page-header__title{margin-block-end:var(--luz-space-2xs);color:var(--luz-text-primary);font-family:var(--luz-font-heading);font-size:var(--luz-text-3xl);font-weight:300;letter-spacing:-1px}.luz-cms-page-header__lead{max-inline-size:600px;color:var(--luz-text-secondary);font-size:var(--luz-text-base)}@media(max-width:640px){.luz-cms-page-header__title{font-size:var(--luz-text-2xl);letter-spacing:-.5px}}.luz-cms-page-header__title:lang(ar){letter-spacing:0}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luz-ds/cms",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "LUZ Design System — the page structure of a blog, a newspaper or any CMS (header, page header, article header, table of contents, footer), built on @luz-ds/core",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./css": "./dist/cms.css",
|
|
9
|
+
"./css/min": "./dist/cms.min.css",
|
|
10
|
+
"./components/*": "./dist/components/*",
|
|
11
|
+
"./classes.json": "./dist/classes.json",
|
|
12
|
+
"./package.json": "./package.json"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/nandovejer/luz.git",
|
|
21
|
+
"directory": "packages/cms"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/nandovejer/luz#readme",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/nandovejer/luz/issues"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"design-system",
|
|
29
|
+
"css",
|
|
30
|
+
"cms",
|
|
31
|
+
"blog",
|
|
32
|
+
"patterns",
|
|
33
|
+
"vanilla"
|
|
34
|
+
],
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"*.css"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@luz-ds/core": "^0.1.0 || ^0.2.0",
|
|
43
|
+
"@luz-ds/catalog": "^0.1.0 || ^0.2.0",
|
|
44
|
+
"@luz-ds/tokens": "^0.1.0 || ^0.2.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"@luz-ds/catalog": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@luz-ds/core": "0.2.0",
|
|
53
|
+
"@luz-ds/catalog": "0.2.0",
|
|
54
|
+
"@luz-ds/tokens": "0.2.0"
|
|
55
|
+
}
|
|
6
56
|
}
|