@carissa-io/webkit-footer 0.0.0-stage → 0.1.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/README.md +103 -2
- package/dist/index.js +55 -0
- package/package.json +54 -4
- package/scss/_footer.scss +118 -0
- package/scss/_variables.scss +56 -0
- package/scss/index.scss +2 -0
package/README.md
CHANGED
|
@@ -1,3 +1,104 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @carissa-io/webkit-footer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The end of a public website's pages: an index of the site (columns of links, each with a heading) and a legal row under a
|
|
4
|
+
1px rule. A layout with slots, not a template: no newsletter form, no back-to-top, no icons or arrows, no gradient, no
|
|
5
|
+
default shadow and no motion. A React component, SCSS-themed, safe on the server, with no runtime dependency.
|
|
6
|
+
|
|
7
|
+
**The component has no strings of its own.** Every text and link comes from the site. The look comes from the theme's
|
|
8
|
+
second stylesheet, `@carissa-io/theme-default/webkit.css`, which apps do not load.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm i @carissa-io/webkit-footer
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Use
|
|
15
|
+
|
|
16
|
+
```jsx
|
|
17
|
+
import { Footer } from '@carissa-io/webkit-footer'
|
|
18
|
+
|
|
19
|
+
<Footer
|
|
20
|
+
as="footer"
|
|
21
|
+
brand={<Logo />}
|
|
22
|
+
description={t('footer_description')}
|
|
23
|
+
nav_label={t('footer_nav_label')}
|
|
24
|
+
columns={[
|
|
25
|
+
{ id: 'product', title: t('product'), links: [{ href: '/passkeys', label: t('passkeys') }, { href: '/pricing', label: t('pricing') }] },
|
|
26
|
+
{ id: 'company', title: t('company'), links: [{ href: '/about', label: t('about') }] },
|
|
27
|
+
]}
|
|
28
|
+
legal={
|
|
29
|
+
<>
|
|
30
|
+
<small>{t('copyright')}</small>
|
|
31
|
+
<a href="/privacy">{t('privacy')}</a>
|
|
32
|
+
</>
|
|
33
|
+
}
|
|
34
|
+
/>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Prop | |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `brand` | a node: the logo or the name, first in the brand block |
|
|
40
|
+
| `description` | a short paragraph under the brand; its measure is limited by `$c-footer-description-max-width` |
|
|
41
|
+
| `columns` | `[{ id, title, links: [{ href, label }] }]`; not an array renders no index |
|
|
42
|
+
| `title_level` | heading level of the column titles, `1` to `6`, default `2`; anything else falls back to `2` |
|
|
43
|
+
| `nav_label` | the accessible name of the index; a non-empty string wraps the index in `<nav aria-label>`, anything else renders a plain `div` |
|
|
44
|
+
| `legal` | a node for the copyright and the legal links, in the second row |
|
|
45
|
+
| `social` | an optional node in the second row, after `legal` |
|
|
46
|
+
| `as` | the root tag, `div` by default; a value that is not a tag name falls back to `div` |
|
|
47
|
+
| `className`, `id`, ... | `className` is appended; unknown props go to the root |
|
|
48
|
+
|
|
49
|
+
Invalid input falls back instead of failing: columns that are not objects or have no usable links are skipped, links without
|
|
50
|
+
a non-empty `href` or without a `label` are skipped, a column without a `title` renders its list without a heading. An empty
|
|
51
|
+
slot (`undefined`, `null`, `false`, `''`) renders nothing, so a footer with only `legal` is valid.
|
|
52
|
+
|
|
53
|
+
### Layout
|
|
54
|
+
|
|
55
|
+
Below `$c-footer-breakpoint` (40rem) everything is one column: brand, then the index, then the legal row. From there, when
|
|
56
|
+
both a brand block and an index exist, they sit side by side. The index is an auto-fit grid whose columns are at least
|
|
57
|
+
`$c-footer-column-min-width` wide, so it adds or drops columns with the space it has and never overflows. The legal row
|
|
58
|
+
wraps. The DOM order is always brand, index, legal row, and nothing reorders it with CSS.
|
|
59
|
+
|
|
60
|
+
## Accessibility
|
|
61
|
+
|
|
62
|
+
- **Landmarks.** The root is a `div` because the page frame (a site shell) usually owns the `footer` landmark. Used on its
|
|
63
|
+
own, pass `as="footer"`: a `footer` that is a descendant of `main` or `article` is not a `contentinfo` landmark, so keep
|
|
64
|
+
it outside them.
|
|
65
|
+
- **Navigation.** Pass `nav_label` (translated by the site) so the index is a named `navigation` landmark ("Site map",
|
|
66
|
+
"Footer"). A page with another `nav` (the header) needs the names to differ. Without `nav_label` no landmark is created.
|
|
67
|
+
- **Lists and headings.** Each column is a `ul` labelled by its heading, so a screen reader announces the group and its
|
|
68
|
+
size. Set `title_level` to fit the page outline (the default is `h2`; use a lower level if the footer sits inside a section).
|
|
69
|
+
- **Focus.** Links are plain `<a>`; the focus ring is the theme's and the footer styles no `outline`. Link text is the label
|
|
70
|
+
you pass: make it descriptive on its own.
|
|
71
|
+
|
|
72
|
+
## Style
|
|
73
|
+
|
|
74
|
+
```scss
|
|
75
|
+
@use '@carissa-io/webkit-footer/scss' with (
|
|
76
|
+
$c-footer-column-min-width: 12rem,
|
|
77
|
+
$c-footer-description-max-width: 36ch
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Classes: `c-footer`, `c-footer__inner`, `c-footer__top` (`--split`), `c-footer__brand`, `c-footer__logo`,
|
|
82
|
+
`c-footer__description`, `c-footer__nav`, `c-footer__column`, `c-footer__title`, `c-footer__list`, `c-footer__item`,
|
|
83
|
+
`c-footer__link`, `c-footer__legal-row`, `c-footer__legal`, `c-footer__social`. Every variable is `!default` (see
|
|
84
|
+
[scss/_variables.scss](scss/_variables.scss)). The defaults are neutral: `inherit`, `transparent`, a `currentcolor` rule, no
|
|
85
|
+
shadow, no gradient, no transition; the theme supplies sizes from its type scale and colours as `var(--c-*)`.
|
|
86
|
+
|
|
87
|
+
| Variable | Default |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `$c-footer-font-family`, `-color`, `-background` | `inherit`, `inherit`, `transparent` |
|
|
90
|
+
| `$c-footer-max-width` | `80rem` (inner block, centred) |
|
|
91
|
+
| `$c-footer-padding-block` | `3rem` |
|
|
92
|
+
| `$c-footer-padding-inline`, `-inline-wide`, `-padding-breakpoint` | `1rem`, `2rem`, `40rem` |
|
|
93
|
+
| `$c-footer-breakpoint` | `40rem` (brand and index side by side from here) |
|
|
94
|
+
| `$c-footer-top-columns`, `-top-gap` | `minmax(0, 1fr) minmax(0, 2fr)`, `3rem` |
|
|
95
|
+
| `$c-footer-column-min-width`, `-column-gap` | `10rem`, `2rem` |
|
|
96
|
+
| `$c-footer-brand-gap` | `1rem` |
|
|
97
|
+
| `$c-footer-description-font-size`, `-line-height`, `-color`, `-max-width` | `inherit`, `1.5`, `inherit`, `40ch` |
|
|
98
|
+
| `$c-footer-title-font-size`, `-font-weight`, `-letter-spacing`, `-text-transform`, `-color`, `-margin-bottom` | `inherit`, `700`, `normal`, `none`, `inherit`, `1rem` |
|
|
99
|
+
| `$c-footer-list-gap` | `0.625rem` |
|
|
100
|
+
| `$c-footer-link-font-size`, `-color`, `-text-decoration`, `-hover-text-decoration` | `inherit`, `inherit`, `none`, `underline` |
|
|
101
|
+
| `$c-footer-rule-color` | `currentcolor` (the 1px rule above the legal row) |
|
|
102
|
+
| `$c-footer-legal-margin-top`, `-padding-top`, `-gap` | `3rem`, `1.5rem`, `0.75rem 1.5rem` |
|
|
103
|
+
| `$c-footer-legal-font-size`, `-color` | `inherit`, `inherit` |
|
|
104
|
+
| `$c-footer-legal-link-color`, `-link-text-decoration` | `inherit`, `underline` (links the site puts in `legal` and `social`; without it they would show the browser blue) |
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/Footer.jsx
|
|
2
|
+
import { useId } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
var LEVELS = [1, 2, 3, 4, 5, 6];
|
|
5
|
+
var TAG = /^[a-z][a-z0-9-]*$/i;
|
|
6
|
+
var join = (...parts) => parts.filter(Boolean).join(" ");
|
|
7
|
+
var filled = (value) => value !== void 0 && value !== null && value !== false && value !== "";
|
|
8
|
+
var text = (value) => typeof value === "string" && value !== "";
|
|
9
|
+
var clean_links = (links) => Array.isArray(links) ? links.filter((link) => link && typeof link === "object" && text(link.href) && filled(link.label)) : [];
|
|
10
|
+
var clean_columns = (columns) => Array.isArray(columns) ? columns.filter((column) => column && typeof column === "object").map((column) => ({ ...column, links: clean_links(column.links) })).filter((column) => column.links.length > 0) : [];
|
|
11
|
+
function Column({ title, links, Heading }) {
|
|
12
|
+
const heading_id = useId();
|
|
13
|
+
const has_title = filled(title);
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", { className: "c-footer__column", children: [
|
|
15
|
+
has_title ? /* @__PURE__ */ jsx(Heading, { className: "c-footer__title", id: heading_id, children: title }) : null,
|
|
16
|
+
/* @__PURE__ */ jsx("ul", { className: "c-footer__list", "aria-labelledby": has_title ? heading_id : void 0, children: links.map((link, index) => /* @__PURE__ */ jsx("li", { className: "c-footer__item", children: /* @__PURE__ */ jsx("a", { className: "c-footer__link", href: link.href, children: link.label }) }, `${link.href}-${index}`)) })
|
|
17
|
+
] });
|
|
18
|
+
}
|
|
19
|
+
function Footer({
|
|
20
|
+
brand,
|
|
21
|
+
description,
|
|
22
|
+
columns,
|
|
23
|
+
title_level = 2,
|
|
24
|
+
nav_label,
|
|
25
|
+
legal,
|
|
26
|
+
social,
|
|
27
|
+
as = "div",
|
|
28
|
+
className = "",
|
|
29
|
+
...rest
|
|
30
|
+
}) {
|
|
31
|
+
const Tag = typeof as === "string" && TAG.test(as) ? as : "div";
|
|
32
|
+
const level = Number(title_level);
|
|
33
|
+
const Heading = `h${LEVELS.includes(level) ? level : 2}`;
|
|
34
|
+
const safe_columns = clean_columns(columns);
|
|
35
|
+
const has_index = safe_columns.length > 0;
|
|
36
|
+
const has_brand = filled(brand) || filled(description);
|
|
37
|
+
const has_legal = filled(legal) || filled(social);
|
|
38
|
+
const Index = text(nav_label) ? "nav" : "div";
|
|
39
|
+
return /* @__PURE__ */ jsx(Tag, { ...rest, className: join("c-footer", className), children: /* @__PURE__ */ jsxs("div", { className: "c-footer__inner", children: [
|
|
40
|
+
has_brand || has_index ? /* @__PURE__ */ jsxs("div", { className: join("c-footer__top", has_brand && has_index && "c-footer__top--split"), children: [
|
|
41
|
+
has_brand ? /* @__PURE__ */ jsxs("div", { className: "c-footer__brand", children: [
|
|
42
|
+
filled(brand) ? /* @__PURE__ */ jsx("div", { className: "c-footer__logo", children: brand }) : null,
|
|
43
|
+
filled(description) ? /* @__PURE__ */ jsx("p", { className: "c-footer__description", children: description }) : null
|
|
44
|
+
] }) : null,
|
|
45
|
+
has_index ? /* @__PURE__ */ jsx(Index, { className: "c-footer__nav", "aria-label": Index === "nav" ? nav_label : void 0, children: safe_columns.map((column, index) => /* @__PURE__ */ jsx(Column, { title: column.title, links: column.links, Heading }, `${column.id ?? ""}-${index}`)) }) : null
|
|
46
|
+
] }) : null,
|
|
47
|
+
has_legal ? /* @__PURE__ */ jsxs("div", { className: "c-footer__legal-row", children: [
|
|
48
|
+
filled(legal) ? /* @__PURE__ */ jsx("div", { className: "c-footer__legal", children: legal }) : null,
|
|
49
|
+
filled(social) ? /* @__PURE__ */ jsx("div", { className: "c-footer__social", children: social }) : null
|
|
50
|
+
] }) : null
|
|
51
|
+
] }) });
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
Footer
|
|
55
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carissa-io/webkit-footer",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Carissa web kit: site footer as a labelled navigation index plus a legal row, as a React component with SCSS variables",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"scss",
|
|
10
|
+
"THIRD-PARTY-NOTICES"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/index.js",
|
|
14
|
+
"./scss": "./scss/index.scss",
|
|
15
|
+
"./scss/*": "./scss/*"
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "esbuild src/index.js --bundle --packages=external --format=esm --jsx=automatic --outfile=dist/index.js",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"lint": "eslint .",
|
|
22
|
+
"prepublishOnly": "node -e \"if (!process.env.GITHUB_ACTIONS) { console.error('Refusing to publish outside GitHub Actions CI: commit and push to main instead.'); process.exit(1); }\" && npm run build"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/carissa-io/webkit-footer.git"
|
|
27
|
+
},
|
|
28
|
+
"license": "UNLICENSED",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=24"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"react": ">=18"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@eslint/js": "^10.0.1",
|
|
37
|
+
"@testing-library/jest-dom": "^7.0.1",
|
|
38
|
+
"@testing-library/react": "^16.3.3",
|
|
39
|
+
"@testing-library/user-event": "^14.6.7",
|
|
40
|
+
"@vitejs/plugin-react": "^6.1.1",
|
|
41
|
+
"esbuild": "^0.28.0",
|
|
42
|
+
"eslint": "^10.12.0",
|
|
43
|
+
"eslint-plugin-react-hooks": "^7.1.1",
|
|
44
|
+
"globals": "^17.13.0",
|
|
45
|
+
"jsdom": "^29.1.1",
|
|
46
|
+
"react": "^19.3.0",
|
|
47
|
+
"react-dom": "^19.3.0",
|
|
48
|
+
"sass-embedded": "^1.105.1",
|
|
49
|
+
"vite": "^8.3.2",
|
|
50
|
+
"vitest": "^4.1.11"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"registry": "https://registry.npmjs.org",
|
|
54
|
+
"access": "public"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
@use 'variables' as *;
|
|
2
|
+
|
|
3
|
+
.c-footer {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
padding-block: $c-footer-padding-block;
|
|
6
|
+
padding-inline: $c-footer-padding-inline;
|
|
7
|
+
font-family: $c-footer-font-family;
|
|
8
|
+
color: $c-footer-color;
|
|
9
|
+
background: $c-footer-background;
|
|
10
|
+
|
|
11
|
+
@media (min-width: $c-footer-padding-breakpoint) {
|
|
12
|
+
padding-inline: $c-footer-padding-inline-wide;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.c-footer__inner {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
max-width: $c-footer-max-width;
|
|
19
|
+
margin-inline: auto;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.c-footer__top {
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: $c-footer-top-gap;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.c-footer__brand {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: $c-footer-brand-gap;
|
|
31
|
+
min-width: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.c-footer__logo {
|
|
35
|
+
min-width: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.c-footer__description {
|
|
39
|
+
margin: 0;
|
|
40
|
+
max-width: $c-footer-description-max-width;
|
|
41
|
+
font-size: $c-footer-description-font-size;
|
|
42
|
+
line-height: $c-footer-description-line-height;
|
|
43
|
+
color: $c-footer-description-color;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.c-footer__nav {
|
|
47
|
+
display: grid;
|
|
48
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, $c-footer-column-min-width), 1fr));
|
|
49
|
+
gap: $c-footer-column-gap;
|
|
50
|
+
min-width: 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.c-footer__column {
|
|
54
|
+
min-width: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.c-footer__title {
|
|
58
|
+
margin: 0 0 $c-footer-title-margin-bottom;
|
|
59
|
+
font-size: $c-footer-title-font-size;
|
|
60
|
+
font-weight: $c-footer-title-font-weight;
|
|
61
|
+
letter-spacing: $c-footer-title-letter-spacing;
|
|
62
|
+
text-transform: $c-footer-title-text-transform;
|
|
63
|
+
color: $c-footer-title-color;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.c-footer__list {
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-direction: column;
|
|
69
|
+
gap: $c-footer-list-gap;
|
|
70
|
+
margin: 0;
|
|
71
|
+
padding: 0;
|
|
72
|
+
list-style: none;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.c-footer__item {
|
|
76
|
+
margin: 0;
|
|
77
|
+
overflow-wrap: break-word;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.c-footer__link {
|
|
81
|
+
font-size: $c-footer-link-font-size;
|
|
82
|
+
color: $c-footer-link-color;
|
|
83
|
+
text-decoration: $c-footer-link-text-decoration;
|
|
84
|
+
|
|
85
|
+
&:hover {
|
|
86
|
+
text-decoration: $c-footer-link-hover-text-decoration;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.c-footer__legal-row {
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-wrap: wrap;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: space-between;
|
|
95
|
+
gap: $c-footer-legal-gap;
|
|
96
|
+
margin-top: $c-footer-legal-margin-top;
|
|
97
|
+
padding-top: $c-footer-legal-padding-top;
|
|
98
|
+
border-top: 1px solid $c-footer-rule-color;
|
|
99
|
+
font-size: $c-footer-legal-font-size;
|
|
100
|
+
color: $c-footer-legal-color;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.c-footer__legal,
|
|
104
|
+
.c-footer__social {
|
|
105
|
+
min-width: 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.c-footer__legal a,
|
|
109
|
+
.c-footer__social a {
|
|
110
|
+
color: $c-footer-legal-link-color;
|
|
111
|
+
text-decoration: $c-footer-legal-link-text-decoration;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@media (min-width: $c-footer-breakpoint) {
|
|
115
|
+
.c-footer__top--split {
|
|
116
|
+
grid-template-columns: $c-footer-top-columns;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Every value is `!default`: set it before the first @use / through `with (...)` and it wins.
|
|
2
|
+
//
|
|
3
|
+
// @use '@carissa-io/webkit-footer/scss' with ($c-footer-column-min-width: 12rem, $c-footer-description-max-width: 36ch);
|
|
4
|
+
//
|
|
5
|
+
// The defaults are neutral: colours inherit the text colour, a transparent background, a rule in currentcolor, no shadow,
|
|
6
|
+
// no gradient, no motion. A theme gives the look (sizes from its type scale, `var(--c-*)` colours). The footer is the quiet
|
|
7
|
+
// end of a page: small type, modest padding, the rule and the whitespace do the work.
|
|
8
|
+
|
|
9
|
+
// Root and container
|
|
10
|
+
$c-footer-font-family: inherit !default;
|
|
11
|
+
$c-footer-color: inherit !default;
|
|
12
|
+
$c-footer-background: transparent !default;
|
|
13
|
+
$c-footer-max-width: 80rem !default; // the inner block, centred
|
|
14
|
+
$c-footer-padding-block: 3rem !default;
|
|
15
|
+
$c-footer-padding-inline: 1rem !default;
|
|
16
|
+
$c-footer-padding-inline-wide: 2rem !default;
|
|
17
|
+
$c-footer-padding-breakpoint: 40rem !default; // where the "wide" inline padding starts
|
|
18
|
+
|
|
19
|
+
// Layout
|
|
20
|
+
$c-footer-breakpoint: 40rem !default; // brand and index sit side by side from here; below it everything is stacked
|
|
21
|
+
$c-footer-top-columns: minmax(0, 1fr) minmax(0, 2fr) !default; // brand, index (side by side)
|
|
22
|
+
$c-footer-top-gap: 3rem !default; // brand to index
|
|
23
|
+
$c-footer-column-min-width: 10rem !default; // the index is an auto-fit grid of columns at least this wide
|
|
24
|
+
$c-footer-column-gap: 2rem !default; // between the columns of the index
|
|
25
|
+
$c-footer-brand-gap: 1rem !default; // brand to description
|
|
26
|
+
|
|
27
|
+
// Description (the measure stays short)
|
|
28
|
+
$c-footer-description-font-size: inherit !default;
|
|
29
|
+
$c-footer-description-line-height: 1.5 !default;
|
|
30
|
+
$c-footer-description-color: inherit !default;
|
|
31
|
+
$c-footer-description-max-width: 40ch !default;
|
|
32
|
+
|
|
33
|
+
// Column titles
|
|
34
|
+
$c-footer-title-font-size: inherit !default;
|
|
35
|
+
$c-footer-title-font-weight: 700 !default;
|
|
36
|
+
$c-footer-title-letter-spacing: normal !default;
|
|
37
|
+
$c-footer-title-text-transform: none !default;
|
|
38
|
+
$c-footer-title-color: inherit !default;
|
|
39
|
+
$c-footer-title-margin-bottom: 1rem !default;
|
|
40
|
+
|
|
41
|
+
// Links
|
|
42
|
+
$c-footer-list-gap: 0.625rem !default;
|
|
43
|
+
$c-footer-link-font-size: inherit !default;
|
|
44
|
+
$c-footer-link-color: inherit !default;
|
|
45
|
+
$c-footer-link-text-decoration: none !default;
|
|
46
|
+
$c-footer-link-hover-text-decoration: underline !default;
|
|
47
|
+
|
|
48
|
+
// Legal row
|
|
49
|
+
$c-footer-rule-color: currentcolor !default; // the 1px rule above the legal row
|
|
50
|
+
$c-footer-legal-margin-top: 3rem !default;
|
|
51
|
+
$c-footer-legal-padding-top: 1.5rem !default;
|
|
52
|
+
$c-footer-legal-gap: 0.75rem 1.5rem !default; // row gap, column gap (the row wraps)
|
|
53
|
+
$c-footer-legal-font-size: inherit !default;
|
|
54
|
+
$c-footer-legal-color: inherit !default;
|
|
55
|
+
$c-footer-legal-link-color: inherit !default; // links the site puts in the legal and social slots (they follow the row, not the browser's blue)
|
|
56
|
+
$c-footer-legal-link-text-decoration: underline !default;
|
package/scss/index.scss
ADDED