1
0
mirror of https://github.com/locomotivemtl/locomotive-boilerplate.git synced 2026-01-15 00:55:08 +08:00

418 Commits

Author SHA1 Message Date
Deven Caron
38e298a70e Merge branch 'master' into feature/wysiwyg 2024-04-03 08:34:12 -04:00
Lucas Bigot
27a41aba66 Add default text dedicated file (#173) 2024-04-03 08:29:24 -04:00
Lucas Bigot
353a38915d Update default headings (#172)
* Move font-size css var into dedicated heading file + Add default mixins

* Rename responsive-type for a more generic name
2024-04-03 08:28:57 -04:00
Lucas Bigot
e8701712b6 Horizontally align iframe 2024-03-28 11:17:17 -04:00
Lucas Bigot
92ba51bef1 Reset custom list markers 2024-03-28 11:00:07 -04:00
Lucas Bigot
ebbb20d0e3 Set iframe full width if no width & height specific html attributes 2024-03-28 10:51:31 -04:00
Lucas Bigot
fae0c2a6dc Set generic spacing rule + Move link color settings into wysiwyg file 2024-03-28 10:32:53 -04:00
Lucas Bigot
2c498c88a0 Remove style properties for th, td
Remove empty style for thead and tr
2024-03-27 21:15:16 -04:00
Lucas Bigot
67dd991e97 Reset default browser styles for ul and ol 2024-03-27 21:04:45 -04:00
Lucas Bigot
a6016cfe57 Remove irrevelant blockquote default style 2024-03-27 20:55:22 -04:00
Lucas Bigot
c00c2d346f Remove iframe default aspect-ratio 2024-03-27 20:43:15 -04:00
Lucas Bigot
7c056ed809 Reset caption above table 2024-03-27 20:38:33 -04:00
Lucas Bigot
c9eab8bf49 Remove specific line-height for ul, ol and p 2024-03-27 20:37:43 -04:00
Lucas Bigot
7395a431fe Remove display and color properties on <a> tag 2024-03-27 20:36:56 -04:00
Lucas Bigot
08df2d9ac4 Remove blockquote line-height property 2024-03-27 20:34:16 -04:00
Lucas Bigot
40c0c30672 Add default wysiwyg file 2024-03-27 18:05:06 -04:00
Lucas Bigot
6d37049989 Fix resize event debounce method + Clean up and re-organize app file 2024-03-26 18:30:36 -04:00
Lucas Bigot
bc3fd3a492 Fix grid-space sass function using calculated vw value 2024-03-26 18:29:48 -04:00
Lucas Bigot
45d8be5525 Rename breakpoints by shortnames (#171)
* Rename breakpoints by shortnames

* Replace `tiny` breakpoint for `xs` in spacing loop

* Add 2xs, 4xl and 5xl breakpoints
2024-03-26 16:50:16 -04:00
Deven Caron
ea8f98a52d Add assets.json and empty directories for scripts and styles 2024-03-26 16:29:33 -04:00
Deven Caron
56bbd9e3c5 Delete assets.json file 2024-03-26 16:29:12 -04:00
Deven Caron
dcb7e91b91 Update node version for vercel 2024-03-26 16:20:50 -04:00
Deven Caron
2b1eb8e0dd Add new files and update .gitignore 2024-03-26 15:44:21 -04:00
Deven Caron
f4afd9c6b2 Delete compiled assets 2024-03-26 15:42:20 -04:00
Lucas Bigot
7578397a8e Merge pull request #170 from locomotivemtl/feature/config-speed
Rename `timing` by `speed`
2024-03-26 15:10:10 -04:00
Lucas Bigot
27effb470d Merge branch 'master' into feature/config-speed 2024-03-26 15:06:16 -04:00
Lucas Bigot
7a91cbce61 Merge pull request #165 from locomotivemtl/feature/css-reset
Modernize css normalize
2024-03-26 15:03:15 -04:00
Lucas Bigot
65a265c0ea Merge branch 'master' into feature/css-reset 2024-03-26 15:02:21 -04:00
Lucas Bigot
afb3a4aa6a Merge pull request #161 from locomotivemtl/feature/svgs-folder
Add dedicated SVG sprite folder
2024-03-26 14:56:03 -04:00
Lucas Bigot
40521c3f2b Merge pull request #169 from locomotivemtl/feature/config-spacing
Rework spacing css config
2024-03-26 14:47:00 -04:00
Lucas Bigot
2d395cf73a Rename timing file and sass function for speed 2024-03-26 14:37:11 -04:00
Lucas Bigot
81d47b88b8 Rename spacer by spacings 2024-03-26 14:06:25 -04:00
Lucas Bigot
c16407c8c1 Add clamp-with-max & size-clamp sass functions 2024-03-26 11:41:23 -04:00
Lucas Bigot
522c9c0bcb Replace vh based spacing values 2024-03-26 11:16:54 -04:00
Chauncey McAskill
ddd12ffc38 Fix inconsistent argument name in grid-space() function in Sass 2024-01-29 15:19:09 -05:00
Chauncey McAskill
9e6d7ae182 Replace deprecated divisions in Sass 2024-01-29 15:17:50 -05:00
Chauncey McAskill
d5bff3ab50 Remove obsolete span() function in Sass 2024-01-29 15:06:58 -05:00
Chauncey McAskill
962ba66b96 Update NPM dependencies
Updated:
- autoprefixer v10.4.13 → v10.4.17
- esbuild v0.17.6 → →0.20.0
- locomotive-scroll v5.0.0-beta.9 → v5.0.0-beta.11
- sass v1.69.5 → v1.70.0
2024-01-29 12:30:58 -05:00
Chauncey McAskill
5b6bca6ce3 Replace deprecated division in '_widths.scss' 2024-01-29 11:37:39 -05:00
Chauncey McAskill
4ae90a5821 Annotate Sass modules section of 'main.scss' 2024-01-29 11:37:18 -05:00
Lucas
31061daf60 Merge pull request #166 from locomotivemtl/feature/viewport-units
Viewport sizes fallbacks
2024-01-22 16:31:21 +01:00
Lucas
ceefeb554e Merge branch 'master' into feature/viewport-units 2024-01-22 16:31:12 +01:00
Lucas Vallenet
276b5eebc0 Update asset version 2024-01-22 16:30:40 +01:00
Jérémy Minié
a37c5b047a Fix PurgeCSS safelist regex 2024-01-16 15:07:09 -05:00
Lucas Vallenet
0af2be4599 Update reset 2024-01-12 12:07:38 +01:00
Lucas Vallenet
98ba8c4972 Update normalize comment 2024-01-12 11:28:42 +01:00
Lucas Vallenet
3f7077b488 Add vh/svh/dvh/lvh fallbacks 2024-01-11 11:45:46 +01:00
Lucas Vallenet
a674a16c4b Remove body margins 2024-01-11 11:27:44 +01:00
Lucas Vallenet
dd2c783938 Modernize css normalize 2024-01-11 11:10:38 +01:00
Deven Caron
61b6222525 Merge pull request #163 from locomotivemtl/chore/update-node-version
Update node version & bump npm packages version
2024-01-05 15:24:22 -05:00
Deven Caron
5acd27d1b0 Compile assets 2024-01-05 09:06:33 -05:00
Deven Caron
9a5a91b221 Update Node version and npm dependencies 2024-01-05 09:06:24 -05:00
Lucas Vallenet
7021666c46 Add dedicated svg folder 2023-12-11 11:43:16 +01:00
Lucas
43c86c3b50 Merge pull request #160 from butterfail/greg/invlerp
Fix invlerp method
2023-12-11 11:10:26 +01:00
Lucas Vallenet
0b4c82ceda Add scss-config dedicated files 2023-12-11 11:02:54 +01:00
Lucas Vallenet
b72fdabe23 Add default z-index value 2023-12-11 11:00:21 +01:00
Lucas Vallenet
f1ebc27a69 Add aspect-ratio scss mixin 2023-12-11 10:58:24 +01:00
Grégoire Ciles
f2898c8c8e Fix invlerp method 2023-11-29 12:27:01 +01:00
Lucas Vallenet
12d65db09f Reverse aspect-ratio condition 2023-11-29 11:10:32 +01:00
Lucas Vallenet
657fd41f70 Update config functions: alpha parameter for colors, multiplier parameter for spacers 2023-11-21 10:03:17 +01:00
Deven Caron
65c486b910 Update locomotive-scroll to v5.0.0-beta.9 2023-11-15 13:55:25 -05:00
Deven Caron
3d0e4d26a2 Update sass version to 1.69.5 2023-11-15 13:53:04 -05:00
Chauncey McAskill
df1a3a6f3c Update sass import in styles.js 2023-09-08 17:11:27 -04:00
Lucas Vallenet
7f1b6dad2e Fix device detection on config.js 2023-09-05 09:40:19 +02:00
Lucas Vallenet
63e46cde26 Comment updates 2023-09-05 09:34:24 +02:00
Lucas Vallenet
6564fb330a Update eases names to match gsap / Add default vars for z-indexes, timings and eases 2023-09-05 09:31:56 +02:00
Chauncey McAskill
b5753148f1 Improve asset versioning task
Add support for "increment" format to increment an integer version number with support for "increment:semver" to increment the build or patch of a SemVer version number.

Usage:

```json
"versions": [
    {
        "format": "increment",
        "key": "version",
        "outfile": "assets.json"
    }
]
```

```jsonc
{
    "version": 16 // → 17
}
```

```json
"versions": [
    {
        "format": "increment:semver",
        "key": "version",
        "outfile": "assets.json"
    }
]
```

```jsonc
{
    "version": "1.0.0" // → 1.0.1
}
```

```jsonc
{
    "version": "1.0.0+1" // → 1.0.0+2
}
```
2023-08-14 16:56:01 -04:00
Lucas Vallenet
7b415af8c2 Fix comments 2023-08-14 10:56:14 +02:00
Lucas Vallenet
dc0bc2042c Create aspect-ratio SCSS mixin polyfill 2023-08-14 10:40:24 +02:00
Chauncey McAskill
e9dbb03207 Fix support for undefined tasks in watch.js
Amends 596ff7a8ee
2023-08-10 11:01:50 -04:00
Chauncey McAskill
95caf9ebb5 Replace window.onload with window.addEventListener()
Since the `window` can only ever have one `onload` value, if ever a third-party script overwrites this property, the application risks never initializing.

By using `addEventListener('load',…)`, the application's bootstrapping logic is queued and is more likely to be initialized.
2023-08-08 15:34:01 -04:00
Chauncey McAskill
596ff7a8ee Fix support for undefined tasks
For example, if there are no `concats` tasks defined in 'loconfig.json', avoid throwing an error.
2023-08-08 14:49:47 -04:00
Deven Caron
70b36052e6 Merge pull request #154 from locomotivemtl/dependabot/npm_and_yarn/socket.io-parser-4.2.4
Bump socket.io-parser from 4.2.2 to 4.2.4
2023-07-31 10:56:07 -04:00
dependabot[bot]
f1e2e2270f Bump socket.io-parser from 4.2.2 to 4.2.4
Bumps [socket.io-parser](https://github.com/socketio/socket.io-parser) from 4.2.2 to 4.2.4.
- [Release notes](https://github.com/socketio/socket.io-parser/releases)
- [Changelog](https://github.com/socketio/socket.io-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io-parser/compare/4.2.2...4.2.4)

---
updated-dependencies:
- dependency-name: socket.io-parser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-31 14:30:51 +00:00
Deven Caron
13735c64f9 Merge pull request #153 from locomotivemtl/feature/update-scroll
Update locomotive scroll v5
2023-07-31 10:30:17 -04:00
Deven Caron
659ef3767b Fix img scroll lazyload $el 2023-07-31 10:29:02 -04:00
Deven Caron
e162af17dd Update LS styles vendor import 2023-07-31 10:28:35 -04:00
Lucas Vallenet
93559a0c84 Add purgeCSS for .u-padding and .u-margin classes | Disable purge on development 2023-07-10 15:40:56 +02:00
Lucas Vallenet
c1bcf7fb0d Fix spacing loop 2023-06-16 10:13:10 +02:00
Lucas Vallenet
d0fcfaac86 Add config.spacers and modify spacing function to add breakpoint based spacers. 2023-06-15 17:28:29 +02:00
Lucas Vallenet
4a958c5fb5 Update grid-column loop with config.breakpoints list and media query functions. Add @to-* modifier 2023-06-15 17:28:06 +02:00
Lucas Vallenet
5e7e92c7f5 Rename z-indexes config / Update easing comment / Move font-face include to document.scss 2023-06-12 16:50:40 +02:00
Lucas Vallenet
380fbd40c3 Update comments 2023-06-12 16:21:57 +02:00
Lucas Vallenet
e16ba2ca16 Import locomotive scroll CSS / Removed unused styles (scroll, scorllbar) / Update DOM Markup / Update doc 2023-06-12 09:36:14 +02:00
Lucas Vallenet
43a5eb1ad3 Update locomotive scroll v5 2023-06-08 15:44:35 +02:00
Lucas Vallenet
99801a2d8b Add dedicated scss config files 2023-06-08 11:48:00 +02:00
Lucas Vallenet
217a1adba7 Merge scss functions / Fix strip-unit 2023-06-08 10:57:59 +02:00
Lucas Vallenet
a11e98e31e Fix js FONT var error 2023-05-22 09:48:34 +02:00
Deven Caron
6ef90dbe11 Merge pull request #149 from locomotivemtl/dependabot/npm_and_yarn/engine.io-6.4.2
Bump engine.io from 6.4.0 to 6.4.2
2023-05-12 10:41:24 -04:00
Deven Caron
6726d665f2 Merge pull request #148 from locomotivemtl/feature/scss-colors
Color as list
2023-05-12 10:39:38 -04:00
Deven Caron
dca6c5de1d Merge branch 'master' into feature/scss-colors 2023-05-12 10:39:10 -04:00
Deven Caron
05a00c4258 Merge pull request #146 from locomotivemtl/feature/css-math
Replace fractions with math.div in scss files
2023-05-12 10:36:33 -04:00
Deven Caron
7517be0e76 Merge pull request #147 from locomotivemtl/feature/js-config
Feature/js config
2023-05-12 10:36:08 -04:00
dependabot[bot]
dcec21adf4 Bump engine.io from 6.4.0 to 6.4.2
Bumps [engine.io](https://github.com/socketio/engine.io) from 6.4.0 to 6.4.2.
- [Release notes](https://github.com/socketio/engine.io/releases)
- [Changelog](https://github.com/socketio/engine.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/engine.io/compare/6.4.0...6.4.2)

---
updated-dependencies:
- dependency-name: engine.io
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 01:31:42 +00:00
Lucas Vallenet
297e0b4ec8 Update color function 2023-04-21 11:34:15 +02:00
Lucas Vallenet
9a2083d894 Color as list with function 2023-04-19 15:37:52 +02:00
Lucas Vallenet
1a81c865ae Config namespaces 2023-04-05 15:06:51 -04:00
Lucas Vallenet
d6b5784cdd Replace fractions with math.div in scss files 2023-04-05 14:40:28 +02:00
Lucas Vallenet
8894664743 Update js config values and use it within whole app 2023-04-05 12:23:25 +02:00
Deven Caron
8aac2ffea6 Merge pull request #132 from locomotivemtl/feature/build-task-chores
Various fixes and changes to build utilities
2023-03-06 09:07:04 -05:00
Chauncey McAskill
349d110dee Revert merging of usrconfig to use let declaration 2023-03-03 13:13:31 -05:00
Chauncey McAskill
7be5e48f22 Fix import of merge util in 'watch.js'
The `merge` function is provided by 'utils/index.js'.
2023-03-03 13:07:47 -05:00
Chauncey McAskill
1ee315663e Fix glob.js and improve documentation
Documented API inconsistencies between supported glob libraries (expected/supported parameters and return types).

Fixed API inconsistencies between 'tiny-glob', 'globby', and 'glob', to match 'fast-glob'.

Fixed broken support for preset options for 'tiny-glob'.
2023-03-03 13:04:22 -05:00
Chauncey McAskill
89bb00790f Update postcss.js documentation 2023-03-03 13:04:22 -05:00
Chauncey McAskill
9db0c71a82 Move helpers/utils exports to end of file
Improves readability by always expecting exports at the end of the file.
2023-03-03 13:04:22 -05:00
Chauncey McAskill
7742bbb9d0 Add block comments to task iteratees 2023-03-03 13:04:22 -05:00
Chauncey McAskill
c9a9209b4b Refactor build utilities
Separated generic functions from build helpers.

Changed:
- Moved 'utils/*.js' to 'helpers/*.js'
- From 'utils/config.js':
  - Moved function `merge` to 'utils/index.js'.
  - Moved function `isObjectLike` to 'utils/index.js'.
- From 'utils/template.js':
  - Moved function `flatten` to 'utils/index.js'.
  - Moved function `escapeRegExp` to 'utils/index.js'.
- From 'tasks/styles.js':
  - Moved function `createPostCSSProcessor` to 'helpers/postcss.js' as `createProcessor`.
- Replaced function `Object.assign` with `merge` for task options parsing in all tasks.
2023-03-03 13:04:22 -05:00
Chauncey McAskill
9d758f3b2c Improve postcss.js
Added constant `supportsPostCSS` to provide a boolean to check if PostCSS is available.
2023-03-03 13:04:22 -05:00
Chauncey McAskill
0738dd6491 Improve glob.js
Added constant `supportsGlob` to provide a boolean to check if a glob function is available.
2023-03-03 13:04:22 -05:00
Chauncey McAskill
a4656f59ed Improve concats.js, scripts.js, svgs.js
Added:
- Condition to cast `includes` into an array.

Removed:
- Variable `files` in favour of reusing `includes` in 'concats.js'.
2023-03-03 13:04:20 -05:00
Deven Caron
7ff6094e40 Move sass to dev dependencies 2023-03-03 10:49:57 -05:00
Chauncey McAskill
3fee6f4888 Update NPM depdencies
Updated:
- browser-sync v2.27.5 → v2.27.11
- esbuild v0.16.17 → v0.17.6
- engine.io v3.5.0 → v6.4.0
- qs v6.2.3 → v6.11.0

Changed:
- Overrode ua-parser-js constraint in browser-sync from `1.0.2` to `~1.0.33` to fix security notice.
2023-02-09 10:52:26 -05:00
Deven Caron
f774482255 Update README node version 2023-02-09 10:21:39 -05:00
Deven Caron
b7d9311ac6 Remove container width; replace with padding 2023-02-09 10:18:47 -05:00
Deven Caron
c22a006079 Merge pull request #139 from locomotivemtl/feature/update-node-version
Update node version to v17.9 and switch from node-sass to sass
2023-02-09 10:15:42 -05:00
Deven Caron
af57ebd9cb Merge branch 'master' into feature/update-node-version 2023-02-09 10:11:24 -05:00
Deven Caron
c82e9916d0 Merge branch 'master' into feature/update-node-version 2023-02-09 10:05:25 -05:00
Deven Caron
943324220a Downgrade to node v17.9 2023-02-09 10:00:31 -05:00
Deven Caron
477cec7763 Merge pull request #141 from locomotivemtl/feature/optimize-grid
Optimise grid-column loops / Use css vars for grid columns
2023-02-09 09:08:35 -05:00
Deven Caron
5d38685460 Merge branch 'master' into feature/optimize-grid 2023-02-09 09:07:35 -05:00
Deven Caron
9079d735bc Merge pull request #138 from locomotivemtl/feature/css-variables
Feature / CSS Variables
2023-02-09 09:02:59 -05:00
Deven Caron
87238fcdd5 Merge branch 'master' into feature/css-variables 2023-02-09 09:01:24 -05:00
Deven Caron
2f75d8f3d2 Merge pull request #142 from locomotivemtl/dependabot/npm_and_yarn/http-cache-semantics-4.1.1
Bump http-cache-semantics from 4.1.0 to 4.1.1
2023-02-07 09:30:26 -05:00
dependabot[bot]
0346a15b57 Bump http-cache-semantics from 4.1.0 to 4.1.1
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-04 05:43:43 +00:00
Deven Caron
a2d658bc13 Remove log to prevent throwing unwanted errors 2023-02-02 10:14:48 -05:00
Deven Caron
7c1b61eda9 Add build config dynamic import assertation type 2023-02-02 10:00:20 -05:00
Lucas Vallenet
1fe30a9837 Optimize grid-column loops / Use css vars for grid columns 2023-02-01 10:23:43 +01:00
Deven Caron
e4ae03a94c Remove unused sass env function 2023-01-31 15:37:40 -05:00
Deven Caron
3cde7d40ee Update readme 2023-01-31 14:15:56 -05:00
Deven Caron
d1d4fb5fe5 Bump node-version & upgrade node-sass to sass 2023-01-31 13:57:51 -05:00
Chauncey McAskill
3cd81bdb3e Improve asset versioning task
Improved logic for replacing the value to allow for simpler regular expression patterns. Lookbehinds and lookaheads are no longer required.
2023-01-13 16:42:47 -05:00
Chauncey McAskill
b6970832a3 Improve asset versioning task
Added support for replacing a string in a file using a regular expression.

The routine uses Node's Readline and Stream modules.

The `outfile` will be renamed with a `~` suffix, then stream each line, writing to a new `outfile`.

On success, the backup file (with `~`) is deleted.

On error, any new file is deleted, then the backup file is renamed without a `~` suffix.

Usage:

```json
"versions": [
    {
        "format": "timestamp",
        "key": "regexp:(?<=\bdefine\('ASSETS_VERSION', )[^\)]+(?=\);)",
        "outfile": "src/bootstrap.php"
    }
]
```

```php
<?php

define( 'ASSETS_VERSION', 1665071717350 );
```
2023-01-13 15:08:50 -05:00
Chauncey McAskill
b8f0a24cdc Update NPM dependencies
Updated:
- esbuild v0.16.13 → v0.16.17
- postcss v8.4.20 → v8.4.21
2023-01-13 14:55:01 -05:00
Chauncey McAskill
0c718a2644 Update Development documentation
Changed:
- Bumped NPM requirement.
- Added note about benefits of using NVM.
- Added note about support for PurgeCSS to Styles task.
- Added details about Versions task.
2023-01-05 10:37:52 -05:00
Lucas Vallenet
be71474633 Remove duplicate / Update functions descriptions 2023-01-05 09:58:01 +01:00
Chauncey McAskill
56d255eac8 Fix NPM dependency constraints on svg-mixer
Changed:
- Fixed svg-mixer constraint from `^2.3.14` to `~2.3.14` to stay within `2.3` range since `2.4.0` appears to be an anomaly.
- Overrode postcss constraint in svg-mixer from `^6.0.21` to `^8.4.20` to fix security notice.
2023-01-04 11:01:40 -05:00
Chauncey McAskill
e7e343e62c Bump NPM requirement to 8+
To take advantage of NPM dependency overrides.
2023-01-04 11:01:40 -05:00
Chauncey McAskill
590e06fc03 Update NPM dependencies
Updated:
- autoprefixer v10.4.12 → v10.4.13
- browser-sync v2.27.10 → v2.27.11
- esbuild v0.14.54 → v0.16.13
- node-sass v7.0.3 → v8.0.0
- postcss v8.4.17 → v8.4.20
2023-01-04 11:01:38 -05:00
Lucas Vallenet
810df92a61 Fix functions.scss error 2023-01-04 14:41:25 +01:00
Lucas Vallenet
4fd7968b86 Fix SCSS syntax error and duplicate 2023-01-04 11:26:56 +01:00
Lucas Vallenet
aba77ea2d9 Add default CSS Variables 2023-01-04 11:21:43 +01:00
Lucas Vallenet
bf28fe21a3 Strip breakpoint unit from responsive-type 2023-01-04 11:02:32 +01:00
Lucas Vallenet
7b3cefd8df Add usefull scss functions 2023-01-04 10:50:36 +01:00
Lucas Bigot
20b167da33 Invert grid-helper visibility condition 2022-11-22 14:51:37 -05:00
Deven Caron
f7ca837782 Disable browsersync ghostMode 2022-11-02 11:15:49 -04:00
Deven Caron
0c8ed9595f Merge pull request #112 from locomotivemtl/feature/grid-helper 2022-10-31 14:34:13 -04:00
arnvvd
eead1d27cd Move grid helper call to global.js 2022-10-31 14:27:18 -04:00
arnvvd
2e3db21ec8 Update dynamic imports condition 2022-10-31 14:25:22 -04:00
arnvvd
9c478f5f7d grid helper refactoring + prepare JS dynamic import + add app-env function for Sass conditions 2022-10-31 14:25:20 -04:00
Jérémy Minié
ebcbb6dc84 Only use GridHelper's margin setting for lateral grid spacing 2022-10-31 14:22:31 -04:00
Lucas Vallenet
b7c49086c9 Add custom grid helper based on CSS custom properties 2022-10-31 14:20:59 -04:00
Chauncey McAskill
9219a4cc0a Rename default function in versions.js task
Renamed from `bumpVersion` to `bumpVersions` for consistency with the default functions of other tasks.
2022-10-13 12:53:32 -04:00
Chauncey McAskill
14afe2295a Improve asset versioning task
Added:
- Support for writing multiple times to the same file.
- Support for random hexadecimal value instead of timestamp.

Usage:

```json
"versions": [
    {
        "format": "timestamp",
        "key": "now",
        "outfile": "./assets.json"
    },
    {
        "format": "hex:8",
        "key": "hex",
        "outfile": "./assets.json"
    }
]
```

```json
{
    "now": 1665071717350,
    "hex": "6ef54181c4ba"
}
```
2022-10-12 12:07:24 -04:00
Deven Caron
1bdd2def8d Compile assets 2022-10-06 14:00:32 -04:00
Deven Caron
84ce496df7 Tweak images size to match block ratio 2022-10-06 14:00:26 -04:00
Deven Caron
05e631dbca Fixed locomotive-scroll rendering glitch 2022-10-06 13:59:42 -04:00
Chauncey McAskill
f8f0a7779c Implement simple asset versioning task
A task to allow one to define zero or more JSON files and keys to create or update with the current timestamp.

By default, the boilerplate will maintain a './assets.json' file which should be imported by the Web framework and applied to compiled assets.
2022-10-06 11:32:04 -04:00
Arnaud Pinot
8e320f2cd0 Merge pull request #120 from locomotivemtl/feature/es6-updates 2022-10-05 16:56:16 -04:00
Arnaud Pinot
a8314d064f Update assets/scripts/utils/maths.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2022-10-05 16:54:36 -04:00
arnvvd
76614e8126 Merge branch 'master' into feature/es6-updates 2022-10-05 16:43:57 -04:00
arnvvd
bed84ce392 Merge branch 'feature/es6-updates' of github.com:locomotivemtl/locomotive-boilerplate into feature/es6-updates 2022-10-05 16:39:30 -04:00
arnvvd
feb2241164 Add documentation for esbuild process.env 2022-10-05 16:39:25 -04:00
arnvvd
b1f5a00b8c Delete transform utils function 2022-10-05 16:38:55 -04:00
Arnaud Pinot
2b30d9ac5c Update assets/scripts/utils/is.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2022-10-05 16:36:20 -04:00
Arnaud Pinot
9e5704238e Update assets/scripts/utils/tickers.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2022-10-05 16:35:23 -04:00
Arnaud Pinot
1ede84e1b1 Update assets/scripts/utils/tickers.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2022-10-05 16:34:49 -04:00
Arnaud Pinot
3a83a3209b Merge pull request #129 from locomotivemtl/feature/eager-fonts
Add support for the CSS Font Loading API
2022-10-05 14:42:00 -04:00
arnvvd
98957eb6c4 Merge branch 'master' of github.com:locomotivemtl/locomotive-boilerplate into feature/eager-fonts 2022-10-05 14:38:55 -04:00
arnvvd
6712d2d24d Remove unused constant 2022-10-05 14:27:36 -04:00
Chauncey McAskill
139a6739f6 Update NPM dependencies
Updated:
- autoprefixer v10.4.4 → v10.4.12
- browser-sync v2.27.9 → v2.27.10
- esbuild v0.14.27 → v0.14.54
- kleur v4.1.4 → v4.1.5
- postcss v8.4.12 → v8.4.17
- purgecss v4.1.3 → v4.1.3
2022-10-05 12:54:05 -04:00
Chauncey McAskill
3272521dba Add constant to collect all eager fonts 2022-10-04 16:56:31 -04:00
Chauncey McAskill
e7f0455ce4 Testing CSS Font Loading API
The code in this commit is not intended for production environments;
it requires further testing.

Added:
- Multiple "Source Sans 3" fonts to test many `FontFace` entries.

Changed:
- Removed quotes from font family name to avoid them being included in `FontFace.family` value.

Notes:
- Replaces hidden `<span>` elements with `FaceFace.load()` and `FaceFace.loaded` to eagerly load fonts.
- Fonts are eagerly using custom `loadFonts()` (see 'app.js').
- Acting upon loaded fonts is done using `whenReady()` (see 'Example.js').
2022-09-27 11:11:31 -04:00
Deven Caron
bf425521c4 Fix "z()" sass function typo 2022-08-25 14:45:24 -04:00
Chauncey McAskill
4bdaa5d085 Fix typo in styles.js
Resolves #125
2022-08-12 14:03:55 -04:00
Deven Caron
a385f6ed11 Merge pull request #108 from locomotivemtl/feature/grid-css
Add grid CSS layout system
2022-06-07 13:13:31 -04:00
Deven Caron
4079752fe0 Add ul,ol condition grid reset styles 2022-06-07 10:46:44 -04:00
Deven Caron
14d7e09b2b Compile assets 2022-06-06 16:43:51 -04:00
Deven Caron
e70bf33409 Update variable names to kebab-case 2022-06-06 16:43:13 -04:00
Deven Caron
8b0926269a Apply suggestions from code review
Co-authored-by: Chauncey McAskill <chauncey@mcaskill.ca>
2022-06-06 16:30:59 -04:00
Deven Caron
8d1b548ad0 Update PurgeCSS import order 2022-06-06 16:28:07 -04:00
Deven Caron
7ca7486913 Fix $container-width conflict 2022-06-06 14:42:25 -04:00
Jérémy Minié
520b75185f Remove unused $container-width SCSS variable 2022-06-06 13:26:47 -04:00
Jérémy Minié
a056a87855 Fix grid.md code sample closure + Link grid doc in README 2022-06-06 13:26:07 -04:00
Deven Caron
9b99a1958b Manually apply some #108 suggestions 2022-06-06 13:26:07 -04:00
Deven Caron
d6193a41fa Apply suggestions from code review
Co-authored-by: Chauncey McAskill <chauncey@mcaskill.ca>
2022-06-06 13:26:07 -04:00
Deven Caron
4fafcb8e1d Update docs/grid.md
Co-authored-by: Chauncey McAskill <chauncey@mcaskill.ca>
2022-06-06 13:26:07 -04:00
Deven Caron
aadc410e44 Change PurgeCSS task message label
Co-authored-by: Chauncey McAskill <chauncey@mcaskill.ca>
2022-06-06 13:26:07 -04:00
Deven Caron
0439b165cf Apply suggestions from code review
Co-authored-by: Chauncey McAskill <chauncey@mcaskill.ca>
2022-06-06 13:26:07 -04:00
Deven Caron
f98eebc9e1 Add global readme grid reference 2022-06-06 13:26:07 -04:00
Deven Caron
cb80a2ed13 Add missing grid readme instructions 2022-06-06 13:26:07 -04:00
Deven Caron
07c3155c29 Compile styles 2022-06-06 13:15:56 -04:00
Deven Caron
c264cb7905 [WIP] Start grid doc 2022-06-06 13:07:57 -04:00
Deven Caron
1050b83326 Add template links 2022-06-06 13:07:57 -04:00
Deven Caron
d0a075ff24 Add css grid system base styles 2022-06-06 13:07:12 -04:00
Deven Caron
ad4a1c7d47 Add PurgeCSS u-gc* tasks 2022-06-06 13:03:06 -04:00
Chauncey McAskill
de6b3d73a1 Merge pull request #124 from GregoireCiles-fix/scss-build-font-faces
* GregoireCiles-fix/scss-build-font-faces:
  Support for building a single font family
  Fix alignment and mixin in _fonts.scss
2022-06-06 11:37:45 -04:00
Grégoire Ciles
e8af22009c Support for building a single font family
Co-authored-by: Chauncey McAskill <chauncey@mcaskill.ca>
2022-06-06 11:36:37 -04:00
Grégoire Ciles
de1a5904a8 Fix alignment and mixin in _fonts.scss 2022-06-06 11:36:31 -04:00
Lucas Vallenet
f527488464 Delete queryClosestParent function 2022-06-02 17:23:06 +02:00
Lucas Vallenet
cf3f40c956 Update functions comments 2022-06-02 16:45:31 +02:00
Lucas Vallenet
ebb55769f9 Remove isEqual and isNumeric functions 2022-06-02 11:09:32 +02:00
Lucas Vallenet
c8d4e7c154 Build scripts and styles with latest updates 2022-06-01 16:26:47 +02:00
Lucas
bce37afb6e Merge pull request #121 from locomotivemtl/feature/scss-font-fallbacks
Add font fallbacks
2022-06-01 16:21:16 +02:00
Lucas
7a23abff92 Merge branch 'master' into feature/scss-font-fallbacks 2022-06-01 16:21:09 +02:00
Lucas
27d8fdee22 Merge pull request #110 from locomotivemtl/feature/icons
Add icon object styles and html example
2022-06-01 16:20:13 +02:00
Lucas
9154deb036 Merge branch 'master' into feature/icons 2022-06-01 16:19:46 +02:00
Lucas
17e8004515 Merge pull request #117 from locomotivemtl/feature/scss-functions
Add Sass functions
2022-06-01 16:17:27 +02:00
Lucas Vallenet
9a461ab4c0 Remove events.js 2022-06-01 14:21:14 +02:00
Lucas Vallenet
6b3edefa48 Reset scripts to master 2022-06-01 11:02:55 +02:00
Lucas Vallenet
fd5efe3531 Update functions comments 2022-06-01 11:02:26 +02:00
Lucas Vallenet
2783fb5138 Reset scripts from master 2022-05-31 13:20:02 +02:00
Lucas Vallenet
f1e4cd2c55 Update comments 2022-05-31 13:19:34 +02:00
Chauncey McAskill
b7d25c5865 Update _fonts.scss
Improved block comments and error for mixins.
2022-05-30 15:00:24 -04:00
Lucas Vallenet
0a199afe01 Add unsaved comments 2022-05-30 16:44:19 +02:00
Lucas Vallenet
8ca570b37a Font fallbacks 2022-05-30 16:41:53 +02:00
Lucas
e5417ff6ab Merge pull request #118 from locomotivemtl/feature/scss-variables-namespace
Update Sass variable names and add easings
2022-05-30 13:10:47 +02:00
Lucas
3a94c6aba9 Merge branch 'master' into feature/scss-variables-namespace 2022-05-30 13:09:26 +02:00
Lucas Vallenet
648109fc9b Reset unrelevant scripts changes to master 2022-05-30 13:04:33 +02:00
Lucas Vallenet
eddc0ee156 Edit logs 2022-05-26 13:42:49 +02:00
Lucas Vallenet
202e4064f8 Remove removeCustomEvent (no use). Add logs 2022-05-26 13:42:38 +02:00
Lucas Vallenet
e20111fd2e Add removeCustomEvent util 2022-05-26 13:32:52 +02:00
Lucas Vallenet
de0c4993cb Add config.js / Add tickers utils / Add events utils 2022-05-26 13:06:27 +02:00
Lucas Vallenet
b162c62930 Remove logo.svg / Remove html example markup / Update scss instructions 2022-05-25 17:13:35 +02:00
Lucas Vallenet
cb27975087 Update maths comments / Add pixel value function 2022-05-25 16:02:15 +02:00
Chauncey McAskill
0b667542f5 Refactor visibility.js
Replaced custom callback stacks for executing handlers on page visibility change with native event listener interface and custom event types.

Added:
- Class `PageVisibility` with methods to disable/enable custom event types and check if feature is enabled.
- Custom event types "visibilityhidden" and "visibilityvisible".
2022-05-25 09:54:01 -04:00
Lucas Vallenet
d7de1b2566 Update scss maths comments 2022-05-25 13:57:30 +02:00
Lucas Vallenet
34bca7d68a Rename z-index layers var and update function 2022-05-25 13:54:03 +02:00
Lucas Vallenet
f44093ec19 Update scss semicolon spacings 2022-05-25 13:47:45 +02:00
Lucas Vallenet
6a4043408b Remove export comment 2022-05-25 13:28:15 +02:00
Lucas Vallenet
92500f908f Add roundNumber util 2022-05-25 13:27:40 +02:00
Lucas Vallenet
d97fa82c77 Remove array util 2022-05-25 13:27:30 +02:00
Lucas Vallenet
ccf813f6be Update functions / ES6 syntax / Add functions comments 2022-05-20 16:51:24 +02:00
Lucas Vallenet
141a8ffa97 Update scss vars namespace and add easings 2022-05-20 13:32:47 +02:00
Lucas Vallenet
e875495928 Add z-index function 2022-05-20 11:44:42 +02:00
Lucas Vallenet
c2db2e1922 Add SCSS Math functions 2022-05-20 11:42:06 +02:00
Lucas
32ba1c0eeb Merge pull request #114 from locomotivemtl/refactor/css-comments
Standardize scss comments
2022-05-18 13:58:18 +02:00
Lucas Vallenet
5199ee2025 Double comments / Paragraphs and lists line-breaks / Wrap block comments / File-level annotations syntax / Remove leading comments 2022-05-17 12:08:01 +02:00
Lucas Vallenet
d6c8fdac23 Standardize scss comments 2022-05-12 16:15:44 +02:00
Deven Caron
15a4f2e64f Merge pull request #111 from locomotivemtl/feature/font-face
Update fontface system with scss lists, function and mixin
2022-05-12 09:41:33 -04:00
Lucas Vallenet
9e35894ef1 Revert comments changes to apply to document.scss only 2022-05-12 11:01:51 +02:00
Lucas Vallenet
cabeba55c0 Fix font-face $dir error | Update description comments to SASS synthax 2022-05-02 16:56:25 +02:00
Lucas Vallenet
47974a77a9 - Merge _fonts.scss to _page.scss
- Rename _page.scss to _document.scss
- Rename $fontfaces to $font-faces for consistency
- Document _fonts.scss mixins and functions
- Create mixins @font-face for one face
2022-05-02 10:30:35 +02:00
Lucas Vallenet
e8b2a86798 Update fontface system with scss lists, function and mixin 2022-04-29 13:51:46 +02:00
Lucas Vallenet
da66f89d7f Add icon object styles and html example 2022-04-29 13:36:54 +02:00
Chauncey McAskill
53beae26b0 Fix missing link in Development documentation
Amends 9a01c0f17f
2022-03-24 13:59:02 -04:00
Chauncey McAskill
9a01c0f17f Update README and documentation
Changed:
- Features, Installation, and Development sections in README.
- Introduction, Configuration, and Tasks in Development.
- Heading levels in Technologies.

Fixed:
- Anchors to option sections in Development.
2022-03-24 13:57:28 -04:00
Deven Caron
97d9f1ec00 Merge pull request #107 from locomotivemtl/feature/documentation
Rewrite README and add documentation
2022-03-24 10:03:58 -04:00
Chauncey McAskill
8b8b267e9d Rewrite README
And split sections from README into dedicated documentation files.

Added:
- "Features" section to summarize the boilerplate's architecture.
- "Getting Started" section to describe how to create a project from the boilerplate.
- "Development" documentation to describe how NPM dependencies, configuring assets and tasks.
- "Technologies" documentation to describe CSS, JS, Locomotive Scroll, ModularLoad, ModularJS.

Changed:
- Moved section "Configuration" to 'docs/development.md'.
- Moved sections "Styles", "Scripts", "Page transitions", and "Scroll detection" to 'docs/technologies.md'.

TODO:
- Move "Environment configuration" section from "Development" to 'feature/local-config' branch.
2022-03-24 09:58:40 -04:00
Deven Caron
822cf7daa8 Merge pull request #106 from locomotivemtl/feature/local-config
Add support for loconfig.local.json
2022-03-24 09:55:02 -04:00
Chauncey McAskill
7f452f1fcc Add example of loconfig.local.json 2022-03-23 14:06:11 -04:00
Chauncey McAskill
5010560ee3 Improve HTTPS/Proxy URL support in watch.js
Added logic to prepend "https://" to the proxy URL if missing.
2022-03-23 13:13:46 -04:00
Chauncey McAskill
0cfb3fbc7d Add support for loconfig.local.json
If a 'loconfig.local.json' file is present (ignored by git), its settings will be merged with those in 'loconfig.json'. Useful for customizing localhost development (see example below).

Added:
- Utility 'config.js' to prepare build settings.
- Function 'merge()' for recursively merging objects and concatenating arrays.

Example:

```json
{
    "paths": {
        "url": "yourlocal.dev"
    },
    "server": {
        "open": true,
        "https": {
            "key": "~/.config/valet/Certificates/{% paths.url %}.key",
            "cert": "~/.config/valet/Certificates/{% paths.url %}.crt"
        }
    }
}
```
2022-03-22 16:40:51 -04:00
Chauncey McAskill
86f88c3f14 Refactor watch.js
Switched to BrowserSync's recommended post-2.0.0 syntax.

Organized logic into functions for easier reading.

Add support for customizing the BrowserSync server from 'loconfig.json'.

Example:

```json
"server": {
    "open": true,
    "https": {
        "key": "~/.config/valet/Certificates/{% paths.url %}.key",
        "cert": "~/.config/valet/Certificates/{% paths.url %}.crt"
    }
}
```
2022-03-22 16:33:19 -04:00
Chauncey McAskill
48bd911804 Refactor template.js
Added:
- Function `resolve()` to process any template tags (in a string) in objects and arrays.

Changed:
- Renamed function `template()` to `resolveValue()`.
- Replaced default export `resolveValue()` with new function `resolve()`.
2022-03-22 16:33:19 -04:00
Chauncey McAskill
d49d3eabb2 Add file comment to notification.js 2022-03-22 16:32:24 -04:00
Chauncey McAskill
28aa6c7de6 Update NPM dependencies
Resolves #105

Updated:
- autoprefixer v10.4.2 → v10.4.4
- browser-sync v2.27.7 → v2.27.9
- esbuild v0.14.21 → v0.14.27
- postcss v8.4.6 → v8.4.12
2022-03-21 17:24:10 -04:00
Chauncey McAskill
38dd28832e Update NPM dependencies
Resolves #102

Updated:
- esbuild v0.14.14 → v0.14.21
- locomotive-scroll v4.1.3 → v4.1.4
- node-notifier v10.0.0 → v10.0.1
- postcss v8.4.5 → v8.4.6
2022-02-15 09:27:37 -05:00
Chauncey McAskill
757c26c772 Fix glob.js file comment 2022-02-15 09:16:03 -05:00
Chauncey McAskill
5e07473396 Make glob optional in concats.js
Added:
- Condition to process includes with glob if it's available.

Changed:
- Utility 'glob.js' to not throw an error if a glob function is unavailable.
2022-02-08 15:18:18 -05:00
Chauncey McAskill
c9056b27d8 Add support for removing duplicates in concats.js
Added:
- Argument `concatOptions` to `concatFiles()` function to customize concatenation.
- Option 'removeDuplicates' to `concatOptions` to remove duplicate paths from the array of globbed paths. Defaults to `true`.

The 'removeDuplicates' is useful for customizing the order of files to concatenate, in which globbing will usually sort paths alphabetically.

This option is convenient when the installed glob library does not support removing duplicates on their own (feature supported in 'fast-glob' and 'glob').

Example:

```
/assets/scripts/vendors/a.js
/assets/scripts/vendors/b.js
/assets/scripts/vendors/c.js
/assets/scripts/vendors/d.js
```

```json
"concats": [
    {
        "includes": [
            "{% paths.scripts.src %}/vendors/c.js",
            "{% paths.scripts.src %}/vendors/*.js"
        ],
        "outfile": "{% paths.scripts.dest %}/vendors.js"
    }
]
```
2022-02-08 14:46:34 -05:00
Chauncey McAskill
38a6c73d2f Add support for customizing glob in concats.js
Added:
- Argument `globOptions` to `concatFiles()` function to customize glob library.
2022-02-08 14:40:00 -05:00
Chauncey McAskill
9d18205b0f Update NPM dependencies
Updated:
- autoprefixer v10.4.0 → v10.4.2
- esbuild v0.13.12 → v0.14.14
- node-sass v6.0.1 → v7.0.1
- postcss v8.3.11 → v8.4.5
2022-01-28 16:00:57 -05:00
Chauncey McAskill
1e7e90c8aa Add support for custom task labels
If ever the basename from the outfile or outdir is an insufficient description.

Example:

```json
"concats": [
    {
        "label": "third-parties",
        "includes": [
            "{% paths.scripts.src %}/vendors/*.js"
        ],
        "outfile": "{% paths.scripts.dest %}/vendors.js"
    }
]
```
2021-12-17 10:39:35 -05:00
Chauncey McAskill
47007cddaf Fix glob.js
Amends 8dec2c69fe

Fixed:
- Forgot to rename all occurrences of 'modules' with 'candidates'.
2021-12-03 15:10:21 -05:00
Chauncey McAskill
5dd3fa843f Add support for watching multiple view paths
Added routine to convert `paths.views` into an array.

Supports a single path as a string, a map of paths, or a list of paths:

```json
"views": "./views/boilerplate/template"
```

```json
"views": {
    "src": "./views/boilerplate/template"
}
```

```json
"views": [
    "./views/boilerplate/template"
]
```
2021-12-03 11:55:35 -05:00
Chauncey McAskill
a5623d3122 Improve comments in watch.js 2021-12-03 11:52:27 -05:00
Chauncey McAskill
67e1fae8f4 Update block comment in styles.js 2021-11-03 17:08:38 -04:00
Chauncey McAskill
a95fe4523c Update postcss.js
Remove extraneous `null` assignment on optional exports.
2021-11-03 16:50:08 -04:00
Chauncey McAskill
eadc414329 Fix merging of default options for PostCSS
Amends 9e3d304654
2021-11-03 16:16:08 -04:00
Chauncey McAskill
b19c18b18c Update NPM dependencies
Updated:
- autoprefixer v10.3.7 → v10.4.0
- browser-sync v2.26.13 → v2.27.7
- esbuild v0.13.4 → v0.13.12
- postcss v8.3.9 → v8.3.11
2021-11-03 13:21:11 -04:00
Chauncey McAskill
db85740a18 Merge pull request #96 from locomotivemtl/mcaskill-refactor-build-options 2021-11-03 13:16:43 -04:00
Chauncey McAskill
5c24fabaa2 Compile assets 2021-11-03 10:50:33 -04:00
Chauncey McAskill
9e3d304654 Add support for task options
Added support for customizing processors in `scripts.js` (esbuild), `styles.js` (node-sass, postcss, autoprefixer), and `svgs.js` (svg-mixer), via arguments for the exported task functions.

Added:
- Constants to decouple shared default options, options for development, and options for production.
- Constants to export default options for development and production as an array of arguments to pass to task functions.

Changed:
- watch.js to apply development args to tasks
2021-11-03 10:49:35 -04:00
Chauncey McAskill
6ded72bc79 Refactor postcss.js
Moved creation of Processor from utility file to styles.js to allow for future customization of `postcss` and `autoprefixer`.
2021-11-03 10:49:35 -04:00
Chauncey McAskill
2a97183d39 Revert NPM lock file version 2
Amends 2316219201
2021-10-29 11:26:12 -04:00
Deven Caron
2316219201 Update Locomotive Scroll package 2021-10-27 10:34:37 -04:00
Deven Caron
d99a69f212 Fix undefined target on LS instance lazyLoad args 2021-10-27 10:33:44 -04:00
Deven Caron
8bc79f715e Merge pull request #97 from locomotivemtl/devenini-add-lazy-loading-utils
Add lazy loading utils & implement in Scroll.js
2021-10-20 14:46:51 -04:00
Deven Caron
62601f22ed Build assets 2021-10-19 14:49:56 -04:00
Deven Caron
082f3b5827 Replace queryClosestParent with Element.prototype.closest 2021-10-19 14:46:38 -04:00
Deven Caron
df567220d5 Syntax changes & coding style 2021-10-19 14:45:24 -04:00
Deven Caron
7d35dcbf28 Precise usage & better comments 2021-10-19 14:41:43 -04:00
Deven Caron
8b40b1a92e build assets 2021-10-18 16:45:40 -04:00
Deven Caron
f2b657568a Add image lazyloading utils 2021-10-18 16:45:31 -04:00
Deven Caron
a28848e8aa Remove toggleLazy call
Adapt lazy-load markup
Add svg viewbox ratio example
2021-10-18 16:44:41 -04:00
Deven Caron
b881003705 Fix stylesheet wrong id 2021-10-18 16:42:36 -04:00
Chauncey McAskill
b55e625457 Improve notification.js
Added:
- Support for passing a callback to node-notifier.
- Shorter timeout on notifications (~12 s → ~5 s).
2021-10-12 16:12:29 -04:00
Chauncey McAskill
25ef6675af Fix syntax of styles.js
Amends 7df0481d05
2021-10-12 16:04:29 -04:00
Chauncey McAskill
7df0481d05 Change writeFile promises in styles.js
Await results of `writeFile()` calls for easier readability of operations.
2021-10-12 12:52:36 -04:00
Chauncey McAskill
e53efd6ebc Update NPM dependencies
Updated:
- autoprefixer v10.3.6 → v10.3.7
- esbuild v0.13.3 → v0.13.4
- postcss v8.3.8 → v8.3.9

Added:
- npm v6.0
2021-10-12 12:52:35 -04:00
Chauncey McAskill
14ec69f26d Update NPM dependencies
Updated:
- autoprefixer v10.3.5 → v10.3.6
- esbuild v0.13.0 → v0.13.3
- postcss v8.3.7 → v8.3.8
2021-10-01 14:12:37 -04:00
Chauncey McAskill
fa8aa98595 Add missing constraints to NPM dependencies
Updated:
- locomotive-scroll v4.1.2
- normalize.css v8.0.1
- svg4everybody v2.1.9
2021-10-01 14:04:27 -04:00
Chauncey McAskill
b24b4e10c4 Update NPM manifest 2021-10-01 14:03:41 -04:00
Chauncey McAskill
21f6acf4a6 Update NPM dependencies
Updated:
- autoprefixer v10.3.4 → v10.3.5
- esbuild v0.12.28 → v0.13.0
- postcss v8.3.6 → v8.3.7
2021-09-22 13:26:28 -04:00
Chauncey McAskill
bbbb49f30b Merge pull request #95 from locomotivemtl/mcaskill-refactor-build
Refactor build tasks and config file
2021-09-21 17:58:47 -04:00
Chauncey McAskill
99e1b3fa93 Change tasks to be the default exports 2021-09-21 17:53:46 -04:00
Chauncey McAskill
548b2c604b Fix messages in styles.js
Fixed:
- Expected file extension from `outfile` for variable `name`.
- Expected structure of `err` in main catch (`err.formatted` is only available when thrown by node-sass).
- Context of error messages when writing final CSS and source map to disk.
2021-09-21 17:53:46 -04:00
Chauncey McAskill
ec9228a337 Refactor glob.js
Added function `importGlob()` to enclose operations and improve error handling.
2021-09-21 17:52:32 -04:00
Chauncey McAskill
8dec2c69fe Improve syntax of glob.js
Changed:
- Renamed variables for clarity.

Fixed:
- Block comment for `createArrayableGlob()`.
2021-09-21 17:52:17 -04:00
Chauncey McAskill
3a65683fd8 Compile assets 2021-09-21 17:52:17 -04:00
Chauncey McAskill
1a2cc7b6ac Fix bad paths in watch.js
Amends d4ded2a64e

Fixed:
- Invalid paths to watch.

Changed:
- Replaced risky string concatenation with Node.js' `path.join()` function.
2021-09-20 17:29:41 -04:00
Chauncey McAskill
e7935211cd Replace non-breaking space in JS imports 2021-09-20 10:54:56 -04:00
Chauncey McAskill
7e8a21f698 Update README and Boilerplate occurrences
Changed "Configuration" section to instruct developers on what occurrences to rename throughout the package.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
7e30939b14 Update Node constraint in README
Amends 1203e54277
2021-09-18 01:16:44 -04:00
Chauncey McAskill
655031cd1b Clean-up README 2021-09-18 01:16:44 -04:00
Chauncey McAskill
d4ded2a64e Refactor build tasks and config file
Changed:
- Renamed 'mconfig.json' to 'loconfig.json'.
- Renamed 'concat.js' to 'concats.js' to represent flexible functionality.
- loconfig.json: Base paths are nested under "paths".
- loconfig.json: Paths for tasks are nested under "tasks".
- Refactored each task to process corresponding entries under "tasks" in 'loconfig.json'.
- watch.js: Changed concats watch to use task's includes.

Added:
- tiny-glob v0.2.9
- Utility 'glob.js' to use dynamic imports to fetch an available glob function from node modules.
- Utility 'template.js' to provide a function to render template tags (`{% ... %}`) in tasks.
- concats.js: Support for concatenating groupes of files.
- scripts.js: Support for ESBuild's "outdir" option.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
589ec99135 Move tasks to a dedicated directory
Moved concat.js, scripts.js, styles.js, svgs.js to 'build/tasks/' directory.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
84286fef66 Improve notification.js
Added:
- Block comment
- Support for additional node-notifier properties.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
6e50bc202d Refactor styles.js
Changed:
- Replaced "fs" callback API with "fs/promises" promise API to centralize catching of errors and easier readability of file.
- Prefixed "fs/promises" with 'node:' URI scheme to target Node.js builtin modules.
- Promisified `sass.render`.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
91109c5221 Refactor concat.js
Changed:
- Replaced "fs" callback API with "fs/promises" promise API to centralize catching of errors and easier readability of file.
- Prefixed "fs/promises" with 'node:' URI scheme to target Node.js builtin modules.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
834c6165b0 Refactor postcss.js
Decoupled import routine from final export to provide a shared instance of the PostCSS processor and for easier readability of file.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
ffece71aac Improve message.js
Added:
- Types "notice" and "warning".
- Support for all but the "waiting" message type to stop a timer.

Changed:
- Improved colors of message types.
- Improved handling of PostCSS errors in styles.js.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
454ae64d07 Make postcss optional in styles.js
Added:
- Utility 'postcss.js' to use dynamic imports to fetch PostCSS and Autoprefixer, if available, and build the Processor object.
- Function `saveStylesheet()` in 'styles.js' to decouple the writing of CSS files and source maps.
- Condition to process with PostCSS if it's available.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
7479444572 Change tasks to async functions 2021-09-18 01:16:44 -04:00
Chauncey McAskill
b46fb31dfe Fix logic for PostCSS processing
Amends 3874d9c451674a9b4f76239a17b4cbf50cbdb9d3

The `fs.access()` condition is unnecessary and won't work if a CSS stylesheet does not exist.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
23e55d6340 Move notification.js to utils directory 2021-09-18 01:16:44 -04:00
Chauncey McAskill
70827b0a7d Add semi-colon to exported functions 2021-09-18 01:16:44 -04:00
Chauncey McAskill
8cff91aa68 Fix syntax typo in concat.js
Amends a55e6e523db4b4c932d214d3e204fa29d9c0e58f
2021-09-18 01:16:44 -04:00
Chauncey McAskill
b24014d8b1 Add autoprefixer and postcss
Added:
- autoprefixer v10.3.4
- postcss v8.3.6

Changed:
- Node Sass options to pass source map to PostCSS.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
e9e0e5784e Refactor build tasks
Decouple static "main" keys in mconfig.json and refactor tasks to support many output files.

Added:
- scripts.js: Array of output files (such as 'app.js') to iterate over to bundle JS files.
- styles.js: Array of input files (such as 'main.css' and 'critical.css') to iterate over to compile Sass files.
- svgs.js: Array of output files (such as 'sprite.svg') to iterate over to compile SVG spritesheets.

Changed:
- mconfig.json: Decouple entry points to individual tasks to allow for more flexibility in projects.
- concat.js: Refactor function to use promises to build list of JS files to concatenate.
- message.js: Replace if statements with switch for improved readability.
- message.js: If timerID provided with "waiting" type, log time.
- watch.js: Change CSS and JS reload watch paths to include all files.
- Sorted imports by path.
2021-09-18 01:16:44 -04:00
Chauncey McAskill
8b4d758443 Fix comments and variable in watch.js
Amends 14d9f47fe0

Fixed:
- Location of comments.
- Variable `serverConfig` to `const`.
2021-09-16 14:01:21 -04:00
Chauncey McAskill
e51c717a3c Renamed BrowserSync variable "bs" to "server" 2021-09-16 13:55:29 -04:00
Chauncey McAskill
0267bc6ebd Revert "proxy" back to "url" for BrowserSync
Amends 14d9f47fe0
2021-09-16 13:54:49 -04:00
Chauncey McAskill
4a5d821965 Merge pull request #90 from MouseEatsCat/master
Remove default proxy
2021-09-16 13:48:38 -04:00
Chauncey McAskill
5cc8a75866 Update NPM dependencies
Added:
- esbuild v0.8.16 → v0.12.28
- kleur v4.1.3 → v4.1.4
- locomotive-scroll v4.0.4 → v4.1.2
- node-notifier v8.0.1 → v10.0.0
- node-sass v5.0.0 → v6.0.1

Removed:
- fs
2021-09-14 18:27:03 -04:00
Chauncey McAskill
1203e54277 Constrain Node to v14.17 2021-09-14 18:20:45 -04:00
Michel Descoteaux
14d9f47fe0 Remove default proxy 2021-06-28 21:33:10 -04:00
Jérémy Minié
72eaf582a5 Tweak spacing classes to use rem straight away 2021-05-06 17:04:43 -04:00
Jérémy Minié
e4d1c0058a Nuke templates unused style folder 💥 2021-05-06 17:04:27 -04:00
Jérémy Minié
bcb7525019 Tweak o-layout gutters to match $unit & $unit-small 2021-05-06 17:03:55 -04:00
Jérémy Minié
03b3d211c8 Add a catalog of easing variables 2021-05-06 17:03:45 -04:00
Chauncey McAskill
0d42f65ff6 Skip init function if stylesheet not found
Instead of throwing an error about a member not being defined or accessed on NULL.
2021-04-09 15:23:45 -04:00
Chauncey McAskill
b62385c4e0 Change Sass $assets-path value for critical.css 2021-03-23 12:29:09 -04:00
Quentin Hocdé
53653b2111 Merge pull request #82 from locomotivemtl/dependabot/npm_and_yarn/ini-1.3.8
Bump ini from 1.3.5 to 1.3.8
2021-03-05 09:57:25 -05:00
Quentin Hocdé
26821492a7 Merge pull request #81 from locomotivemtl/dependabot/npm_and_yarn/urijs-1.19.6
Bump urijs from 1.19.2 to 1.19.6
2021-03-05 09:57:15 -05:00
Quentin Hocdé
5d1c5a17f5 Merge pull request #80 from locomotivemtl/dependabot/npm_and_yarn/node-notifier-8.0.1
Bump node-notifier from 8.0.0 to 8.0.1
2021-03-05 09:57:04 -05:00
dependabot[bot]
0071b9d790 Bump ini from 1.3.5 to 1.3.8
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-05 14:45:35 +00:00
dependabot[bot]
ebda397455 Bump urijs from 1.19.2 to 1.19.6
Bumps [urijs](https://github.com/medialize/URI.js) from 1.19.2 to 1.19.6.
- [Release notes](https://github.com/medialize/URI.js/releases)
- [Changelog](https://github.com/medialize/URI.js/blob/gh-pages/CHANGELOG.md)
- [Commits](https://github.com/medialize/URI.js/compare/v1.19.2...v1.19.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-05 14:45:29 +00:00
dependabot[bot]
c94f7ca88e Bump node-notifier from 8.0.0 to 8.0.1
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-05 14:45:26 +00:00
Quentin Hocdé
f52b073263 Merge pull request #79 from locomotivemtl/update-compilation-2020
Update compilation
2021-03-05 09:44:46 -05:00
Quentin Hocdé
b8b056dbe0 Merge branch 'update-compilation-2020' of github.com:locomotivemtl/locomotive-boilerplate into update-compilation-2020 2021-03-05 09:31:02 -05:00
Quentin Hocdé
fbe2a6badf Fix app.js coding style and rename css id 2021-03-05 09:30:54 -05:00
Quentin Hocdé
e687e52cd2 Update build/styles.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:27:47 -05:00
Quentin Hocdé
3cf62e80f7 Update build/styles.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:27:37 -05:00
Quentin Hocdé
a6efa6bcb1 Update build/styles.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:27:25 -05:00
Quentin Hocdé
85a2784a11 Update build/styles.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:27:17 -05:00
Quentin Hocdé
65a2e64474 Update build/styles.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:27:06 -05:00
Quentin Hocdé
2cfe06ea1d Update build/scripts.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:58 -05:00
Quentin Hocdé
b1d90327a3 Update build/scripts.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:50 -05:00
Quentin Hocdé
41b8030d9e Update build/scripts.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:42 -05:00
Quentin Hocdé
d2d294e145 Update build/notification.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:34 -05:00
Quentin Hocdé
f39a5f0a75 Update build/concat.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:25 -05:00
Quentin Hocdé
6a6f2cfa21 Update build/concat.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:18 -05:00
Quentin Hocdé
0e8134629a Update build/concat.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:26:10 -05:00
Quentin Hocdé
5ab2d41525 Update build/utils/message.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:25:55 -05:00
Quentin Hocdé
2d095ef973 Update build/svgs.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:25:50 -05:00
Quentin Hocdé
89b7d9523b Merge branch 'update-compilation-2020' of github.com:locomotivemtl/locomotive-boilerplate into update-compilation-2020 2021-03-05 09:25:24 -05:00
Quentin Hocdé
ad81a8e97f Update package.json node version 2021-03-05 09:25:16 -05:00
Quentin Hocdé
bddbaaed1c Update build/utils/message.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:24:18 -05:00
Quentin Hocdé
5f20fe0e43 Update build/svgs.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:24:04 -05:00
Quentin Hocdé
718feed2c7 Update build/concat.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:23:55 -05:00
Quentin Hocdé
11b9fa7a7d Update assets/scripts/modules/Scroll.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:23:45 -05:00
Quentin Hocdé
ad01d00751 Update assets/scripts/modules/Load.js
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:23:32 -05:00
Quentin Hocdé
31c803d14d Update README.md
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:23:22 -05:00
Quentin Hocdé
6027f8d927 Update .editorconfig
Co-authored-by: Chauncey McAskill <chauncey@locomotive.ca>
2021-03-05 09:23:11 -05:00
Quentin Hocdé
7cc8cee0fd Updates coding styles Scroll.js and app.js 2021-03-05 09:22:43 -05:00
Quentin Hocdé
65d1ead6e7 Fix indentation mconfig and packages 2021-03-05 09:19:42 -05:00
Quentin Hocdé
f7a2f8b219 Update readme (add node version requirements) and update .editorconfig 2021-03-04 12:24:35 -05:00
Quentin Hocdé
5bd1ca268f Update notification 2021-01-18 14:31:41 -05:00
Quentin Hocdé
f67d4c0c41 Add error notification for styles 2020-12-11 16:00:36 -05:00
Quentin Hocdé
f15ec08784 Update notification + add built time + add nvmrc 2020-12-11 10:41:07 -05:00
Quentin Hocdé
6ab44c64a9 add indication for svg favicon and darkmode 2020-12-03 16:25:05 -05:00
Quentin Hocdé
8e5c4e5c83 Update comments 2020-11-27 16:15:36 -05:00
Quentin Hocdé
2e7bb3b482 Update tasks - remove gulp (replaced by node scripts, working with mconfig) + esbuild (no more es5 support) + add critical css in config file 2020-11-27 16:01:54 -05:00
Quentin Hocdé
e686689b52 Add shuffle function in array utils 2020-11-25 15:10:53 -05:00
Chauncey McAskill
46797cbd6d Update isDebug condition in environment.js
Check if the attribute exists instead of a truthy value.
2020-11-16 10:02:28 -05:00
Joel Alphonso
20d08c3d4b Update .editorconfig
Increase indentation for json and yml to 4 spaces
2020-11-02 16:17:44 -05:00
Deven Caron
57c3e72a06 Merge pull request #75 from locomotivemtl/develop
Minor cross-browser enhancements & quality of life changes 🤠
2020-10-26 16:13:59 -04:00
Deven Caron
43fc62950a Build 2020-10-26 15:28:35 -04:00
Deven Caron
80e1614508 Remove browser-sync new window & ghostMode 2020-10-26 15:28:31 -04:00
Deven Caron
55dc6c029c Make global font-size relative to $font-size 2020-10-26 15:27:30 -04:00
Deven Caron
a3001fe3b1 Fix README selector example 2020-10-26 15:26:52 -04:00
Deven Caron
c24ba3fdc1 Remove multiple Element.classList.add values (not compatible with IE11) 2020-10-26 15:26:15 -04:00
Deven Caron
59243317a7 Add more polyfills for cross-browser compatibility 2020-10-26 15:23:45 -04:00
Antoine Boulanger
6ae89d6621 Add npm scripts to run gulp tasks, update readme to remove gulp global dependency 2020-05-27 10:28:39 -04:00
Antoine Boulanger
e910afc384 Change async stylesheet method, check stylesheet onload before init app 2020-05-26 15:22:14 -04:00
Antoine Boulanger
a110cc7ae2 Add font-smoothing 2020-03-03 08:53:10 -05:00
Pier-Luc Cossette
a967b864e3 Remove html overflow-y: scroll 2020-01-20 15:49:33 -05:00
Antoine Boulanger
cc181ed26c Fix polyfill link, update babel polyfill, add preload to css with inline polyfill, add defer to scripts, move lazy load demo to images.html 2019-10-17 09:08:11 -04:00
Antoine Boulanger
47b667bd95 Remove vs from package.json 2019-10-17 09:04:35 -04:00
Jérémy Minié
61c9c0ac6f Add basic scroll-related lazy loading system w/ examples + Fix scrolling issues by putting header inside o-scroll + Use data-scroll-section 2019-09-25 16:25:14 -04:00
Antoine Boulanger
680d6af675 Add abortcontroller to polyfill.io and remove static file 2019-09-03 14:16:08 -04:00
Antoine Boulanger
3ed1175aaf Change loco-scroll version in package.json and add uppercase to import, add forEach to polyfill 2019-08-08 11:18:18 -04:00
Antoine Boulanger
9058945b1a Merge pull request #68 from locomotivemtl/baker-components
Create heading, form and button components with example
2019-07-25 09:10:47 -04:00
Antoine Boulanger
1f589add29 Create heading, form and button component, remove objects, add form example to page.html, add rem to container, remove pjax scss, add scroll object. 2019-07-24 16:28:56 -04:00
Antoine Boulanger
d2db947fd1 Update readme scroll section 2019-07-19 16:37:46 -04:00
Antoine Boulanger
88dd4dde3b Change favicons 2019-07-19 16:08:08 -04:00
Antoine Boulanger
41c3fe4b49 Remove jQuery and scrollTo util 2019-07-19 16:00:31 -04:00
Antoine Boulanger
9836c462b2 Update locomotive-scroll to v3: update scroll.js, add scrollbar css, remove copy task 2019-07-19 15:57:34 -04:00
Quentin Hocdé
cb49c03cca rename APP_NAME constant 2019-07-18 11:25:03 -04:00
Quentin Hocdé
6324f7ee82 Update debug attribute (now with vanilla) 2019-07-18 11:23:06 -04:00
Quentin Hocdé
883e4d202e Update environment file 2019-07-18 11:21:17 -04:00
Quentin Hocdé
5da3bcd961 add getTranslate function in utils 2019-07-04 10:52:04 -04:00
Quentin Hocdé
26cccc7d92 Add transform function in utils 2019-06-26 16:39:03 -04:00
Deven Caron
ce8582c0a4 Add ol reset style 2019-06-26 14:13:26 -04:00
Deven Caron
ee258f5d5f Remove u-list-reset mixin 2019-06-26 14:13:15 -04:00
Deven Caron
cf9a0a2705 Add some basic reset styles (ul, p, figure) 2019-06-26 14:04:13 -04:00
Quentin Hocdé
e6dec31198 Add waiting cursor on loading 2019-06-26 09:32:15 -04:00
Jérémy Minié
7d47ae0d82 Fix small warning in app.js + Add useful methods to html.js + Add maths.js to utils + Build 2019-06-25 14:21:03 -04:00
Antoine Boulanger
206ced5b10 Add .browserslistrc 2019-06-05 14:28:56 -04:00
Antoine Boulanger
d89a242e60 Merge branch 'v2' 2019-05-23 10:35:11 -04:00
Antoine Boulanger
d166261d0a Add loco scroll v2, update load module and app, update html, add nomodule polyfills script tags 2019-05-23 10:06:45 -04:00
Chauncey McAskill
ea5c63744e Fix family.scss
Fixed:
- Typo in filename
- Indentation of contents
2019-05-23 10:06:24 -04:00
Antoine Boulanger
52db1cc63e Fix ratio utility 2019-04-19 11:47:29 -04:00
Antoine Boulanger
6d8954563a Clean ratio object, create ratio utility, import ratio and width by default 2019-04-19 11:45:15 -04:00
Antoine Boulanger
d9eb8364dc Complete rewrite of readme for v2, change styles base folder name for elements 2019-03-31 16:39:37 -04:00
Antoine Boulanger
88aa667090 Start adding modularjs & modularload, start updating readme, update html files, change jquery cdn, remove IE from babelrc 2019-03-24 17:15:47 -04:00
Jérémy Minié
2b176132d3 @joel Fixed deleteModules splice : deleteCount param wasn't present, causing all modules with index > i to be removed from this.currentModules. Fortunately, this was only happening if a scope was given to deleteModules. 2019-03-14 14:13:34 -04:00
145 changed files with 15612 additions and 2898 deletions

View File

@@ -1,13 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"ie": "11"
},
"useBuiltIns": "usage"
}
]
]
}

1
.browserslistrc Normal file
View File

@@ -0,0 +1 @@
defaults

View File

@@ -9,9 +9,8 @@ indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
[*.{md,markdown}]
trim_trailing_whitespace = false
[{*.yml,*.json}]
indent_size = 2
indent_style = space
[*.{ms,mustache}]
insert_final_newline = false

14
.gitignore vendored
View File

@@ -1,3 +1,17 @@
node_modules
.DS_Store
Thumbs.db
loconfig.*.json
!loconfig.example.json
.prettierrc
www/assets/scripts/app.js
www/assets/scripts/app.js.map
www/assets/scripts/vendors.js
www/assets/styles/main.css
www/assets/styles/main.css.map
www/assets/styles/critical.css
www/assets/styles/critical.css.map
assets.json

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
v20.10

232
README.md
View File

@@ -1,158 +1,100 @@
Locomotive's Front-end Boilerplate
==================================
<p align="center">
<a href="https://github.com/locomotivemtl/locomotive-boilerplate">
<img src="https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png" height="140">
</a>
</p>
<h1 align="center">Locomotive Boilerplate</h1>
<p align="center">Front-end boilerplate for projects by <a href="https://locomotive.ca/">Locomotive</a>.</p>
Front-end boilerplate for projects by [Locomotive][locomtl].
## Features
* Uses a custom [task runner](docs/development.md) for handling assets.
* Uses [BrowserSync] for fast development and testing in browsers.
* Uses [Sass] for a feature rich superset of CSS.
* Uses [ESBuild] for extremely fast processing of JS/ES modules.
* Uses [SVG Mixer] for processing SVG files and generating spritesheets.
* Uses [ITCSS] for a sane and scalable CSS architecture.
* Uses [Locomotive Scroll] for smooth scrolling with parallax effects.
* Uses a custom [grid system](docs/grid.md) for layout creation.
Learn more about [languages and technologies](docs/technologies.md).
## Getting started
Make sure you have the following installed:
* [Node] — at least 17.9, the latest LTS is recommended.
* [NPM] — at least 8.0, the latest LTS is recommended.
> 💡 You can use [NVM] to install and use different versions of Node via the command-line.
```sh
# Clone the repository.
git clone https://github.com/locomotivemtl/locomotive-boilerplate.git my-new-project
# Enter the newly-cloned directory.
cd my-new-project
```
Then replace the original remote repository with your project's repository.
Then update the following files to suit your project:
* [`README.md`](README.md):
The file you are currently reading.
* [`package.json`](package.json):
* Package name: `@locomotivemtl/boilerplate`
* Package title: `Locomotive Boilerplate`
* [`package-lock.json`](package-lock.json):
* Package name: `@locomotivemtl/boilerplate`
* [`loconfig.json`](loconfig.json):
* BrowserSync proxy URL: `locomotive-boilerplate.test`
Remove `paths.url` to use BrowserSync's built-in server which uses `paths.dest`.
* View path: `./views/boilerplate/template`
* [`environment.js`](assets/scripts/utils/environment.js):
* Application name: `Boilerplate`
* [`site.webmanifest`](www/site.webmanifest):
* Manifest name: `Locomotive Boilerplate`
* Manifest short name: `Boilerplate`
* HTML files:
* Page title: `Locomotive Boilerplate`
## Installation
```sh
# install mbp and gulp
npm install mbp gulp@next -g
# Switch to recommended Node version from .nvmrc
nvm use
# Install dependencies from package.json
npm install
```
## Usage
## Development
```sh
# init your project
mbp init locomotivemtl/locomotive-boilerplate <directory>
# Start development server, watch for changes, and compile assets
npm start
# run default watch task
gulp
# Compile and minify assets
npm run build
```
## Configuration
Change the mentions of `boilerplate` for your project's name in
- `mconfig.json`
- `assets/scripts/utils/environment.js`
Learn more about [development and building](docs/development.md).
## CSS
## Documentation
- We use [Sass](http://sass-lang.com) for our CSS Preprocessor
- [itcss](http://itcss.io) CSS architecture
- More Minimal BEM like CSS Syntax: `.block_element -modifier`
- [More Transparent UI Code with Namespaces](http://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces)
### Sass import order
* **Settings:** Global variables, site-wide settings, config switches, etc.
* **Tools:** Site-wide mixins and functions.
* **Generic:** Low-specificity, far-reaching rulesets (e.g. resets).
* **Base:** Unclassed HTML elements (e.g. `a {}`, `blockquote {}`, `address {}`).
* **Objects:** Objects, abstractions, and design patterns (e.g. `.o-media {}`).
* **Components:** Discrete, complete chunks of UI (e.g. `.c-carousel {}`).
* **Utilities:** High-specificity, very explicit selectors. Overrides and helper
classes (e.g. `.u-hidden {}`).
### Grid
We use [inuitcss](https://github.com/inuitcss/inuitcss/tree/6eb574fa604481ffa36272e6034e77467334ec50) layout and width system. We are using a inline-block grid system.
Insert a `.o-layout` block and add `.o-layout_item` elements inside it. By default `o-layout_item` made 100%.
You can define different fractions in `/tools/_widths.scss` (`$widths-fractions`)
If you want a 2 columns grid, just add `.u-1/2` on your 2 `.o-layout_item`
If you want to adapt columns by media queries, by example a 2 columns grid for 1000px + resolutions, and one columns in block under 1000px :
**HTML**
```
<div class="o-layout">
<div class="o-layout_item u-1/2@from-medium">
first colum
</div>
<div class="o-layout_item u-1/2@from-medium">
second colum
</div>
</div>
```
**CSS** (`/tools/_widths.scss`)
```
.u-1\/2\@from-medium {
@media (min-width: $from-medium) {
width: span(1/2);
}
}
```
### Form
We included some basic CSS styles and resets to the form elements so we can easily have custom style form elements that work on every browsers.
*[Demo][demo-form]*
## JavaScript
- We use HTML data attributes to init our JavaScript modules: `data-module`
- All DOM related JavaScript is hooked to `js-` prefixed HTML classes
- [jQuery](https://jquery.com) is globally included
[locomtl]: https://locomotive.ca
[demo-grid]: https://codepen.io/AntoineBoulanger/pen/EaLNxe
[demo-form]: https://codepen.io/AntoineBoulanger/pen/uBJmi
## Page transitions
We use [Pjax](https://github.com/MoOx/pjax) by MoOx.
### Setup
1. Create a wrapper : `.js-pjax-wrapper` and a container `.js-pjax-container` inside. When a transition is launched, the new container is put inside the wrapper, and the old one is remove.
2. Main settings are set inside `assets/scripts/transitions/TransitionManager.js`
3. `BaseTransition` is launched by default, to set a new transition (like `CustomTransition`) :
- create a new class `TestTransition.js` witch extends `BaseTransition` in `assets/scripts/transitions/`
- add a line in `assets/scripts/transitions/transitions.js` to add your transition
- use it like : `<a href="/yourUrl" data-transition="TestTransition">My page</a>`
- Enjoy and made everything you want in your transition, check `BaseTransition.js` or `CustomTransition.js` like example
### Schema
Legend
- `[ ]` : listener
- `*` : trigger event
`[pjax:send]` -> (transition) launch()
`[pjax:switch]` (= new view is loaded) -> (BaseTransition) `hideView()` -> hide animations & `*readyToRemove`
`[readyToRemove]` -> `remove()` -> delete modules, remove oldView from the DOM, innerHTML newView, init modules, `display()`
`display()` -> (BaseTransition) `displayView()` -> display animations & `*readyToDestroy`
-> init new modules
`[readyToRemove]` -> reinit()
## Locomotive Scroll
![experimental](https://img.shields.io/badge/stability-experimental-orange.svg)
- [locomotive-scroll](https://github.com/locomotivemtl/locomotive-scroll)
### Configuration
- Create a `.o-scroll` container with `data-module="Scroll"`
- in the module `Scroll.js` you have a basic initialisation
### Options
Options | Type | Description
--- | --- | ---
container | $element | Scroll container (with the smooth scroll, this container will be transform)
selector | String | Every elements will be check by the scroll, can be affect by a followed data attributes
smooth | Boolean | If you want a smooth scroll
smoothMobile | Boolean | If you want a smooth scroll on mobile
mobileContainer | $element | Scroll container on mobile, document by default
getWay | Boolean | if true, the animate will determine if you scroll down or scroll up
getSpeed | Boolean | if true, the animate will calcul the velocity of your scroll. Access with `this.scroll.y`
### Data attributes
Data | Value | Description
--- | --- | ---
data-speed | number | Speed of transform for parallax elements
data-repeat | false | Determine if the "In View" class is added one or each times
data-inview-class | is-show | CSS Class when the element is in view.
data-position | top/bottom | Trigger from top/bottom of the window instead of the default from bottom to top
data-target | #id, .class | Trigger from another element
data-horizontal | false | Use transformX instead of transformY
data-sticky | false | Set $element sticky when it's in viewport
data-sticky-target | #id | Stop the element stick when the target is in viewport
data-callback | `test.Scroll(test:0)` | trigger event, with options way wich return "leave" or "enter" when $element is in viewport
data-viewport-offset | i,j | value between 0 to 1 (0.3 to start at 30% of the bottom of the viewport), useful to trigger a sequence of callbacks. (i : value wich start at the bottom, j : start at the top, j is optional)
* [Development and building](docs/development.md)
* [Languages and technologies](docs/technologies.md)
* [Grid system](docs/grid.md)
[BrowserSync]: https://npmjs.com/package/browser-sync
[ESBuild]: https://npmjs.com/package/esbuild
[ITCSS]: https://itcss.io/
[Locomotive Scroll]: https://npmjs.com/package/locomotive-scroll
[modularJS]: https://npmjs.com/package/modujs
[modularLoad]: https://npmjs.com/package/modularload
[Sass]: https://sass-lang.com/
[SVG Mixer]: https://npmjs.com/package/svg-mixer
[Node]: https://nodejs.org/
[NPM]: https://npmjs.com/
[NVM]: https://github.com/nvm-sh/nvm

View File

@@ -1,161 +1,137 @@
import { APP_NAME, $document, $pjaxWrapper } from './utils/environment';
import globals from './globals';
import { arrayContains, removeFromArray } from './utils/array';
import { getNodeData } from './utils/html';
import { isFunction } from './utils/is';
// Basic modules
import modular from 'modujs';
import * as modules from './modules';
import globals from './globals';
import { debounce } from './utils/tickers';
import { $html } from './utils/dom';
import { ENV, FONT, CUSTOM_EVENT, CSS_CLASS } from './config'
import { isFontLoadingAPIAvailable, loadFonts } from './utils/fonts';
const MODULE_NAME = 'App';
const EVENT_NAMESPACE = `${APP_NAME}.${MODULE_NAME}`;
const app = new modular({
modules,
});
export const EVENT = {
INIT_MODULES: `initModules.${EVENT_NAMESPACE}`,
INIT_SCOPED_MODULES: `initScopedModules.${EVENT_NAMESPACE}`,
DELETE_SCOPED_MODULES: `deleteScopedModules.${EVENT_NAMESPACE}`
};
function init() {
bindEvents();
globals();
setViewportSizes();
class App {
constructor() {
this.modules = modules;
this.currentModules = [];
app.init(app);
$document.on(EVENT.INIT_MODULES, (event) => {
this.initGlobals(event.firstBlood)
.deleteModules(event)
.initModules(event);
});
$document.on(EVENT.INIT_SCOPED_MODULES, (event) => {
this.initModules(event);
});
$document.on(EVENT.DELETE_SCOPED_MODULES, (event) => {
this.deleteModules(event);
});
}
$html.classList.add(CSS_CLASS.LOADED, CSS_CLASS.READY);
$html.classList.remove(CSS_CLASS.LOADING);
/**
* Destroy all existing modules or a specific scope of modules
* @param {Object} event The event being triggered.
* @return {Object} Self (allows chaining)
* Debug focus
*/
deleteModules(event) {
let destroyAll = true;
let moduleIds = [];
// Check for scope first
if (event.$scope instanceof jQuery && event.$scope.length > 0) {
// Modules within scope
const $modules = event.$scope.find('[data-module]');
// Determine their uids
moduleIds = $.makeArray($modules.map(function(index) {
return $modules.eq(index).data('uid');
}));
if (moduleIds.length > 0) {
destroyAll = false;
} else {
return this;
}
}
// Loop modules and destroying all of them, or specific ones
let i = this.currentModules.length;
while (i--) {
if (destroyAll || arrayContains(moduleIds, this.currentModules[i].uid)) {
removeFromArray(moduleIds, this.currentModules[i].uid);
this.currentModules[i].destroy();
this.currentModules.splice(i);
}
}
return this;
}
// document.addEventListener(
// "focusin",
// function () {
// console.log('focused: ', document.activeElement)
// }, true
// );
/**
* Execute global functions and settings
* Allows you to initialize global modules only once if you need
* (ex.: when using Barba.js or SmoothState.js)
* @return {Object} Self (allows chaining)
* Eagerly load the following fonts.
*/
initGlobals(firstBlood) {
globals(firstBlood);
return this;
}
if (isFontLoadingAPIAvailable) {
loadFonts(FONT.EAGER, ENV.IS_DEV).then((eagerFonts) => {
$html.classList.add(CSS_CLASS.FONTS_LOADED);
/**
* Find modules and initialize them
* @param {Object} event The event being triggered.
* @return {Object} Self (allows chaining)
*/
initModules(event) {
// Elements with module
let $moduleEls = [];
// If first blood, load all modules in the DOM
// If scoped, render elements with modules
// If Barba, load modules contained in Barba container
if (event.firstBlood) {
$moduleEls = $document.find('[data-module]');
} else if (event.$scope instanceof jQuery && event.$scope.length > 0) {
$moduleEls = event.$scope.find('[data-module]');
} else if (event.isPjax) {
$moduleEls = $pjaxWrapper.find('[data-module]');
}
// Loop through elements
let i = 0;
const elsLen = $moduleEls.length;
for (; i < elsLen; i++) {
// Current element
let el = $moduleEls[i];
// All data- attributes considered as options
let options = getNodeData(el);
// Add current DOM element and jQuery element
options.el = el;
options.$el = $moduleEls.eq(i);
// Module does exist at this point
let attr = options.module;
// Splitting modules found in the data-attribute
let moduleIdents = attr.split(/[,\s]+/g);
// Loop modules
let j = 0;
let modulesLen = moduleIdents.length;
for (; j < modulesLen; j++) {
let moduleAttr = moduleIdents[j];
if (typeof this.modules[moduleAttr] === 'function') {
let module = new this.modules[moduleAttr](options);
this.currentModules.push(module);
module.init();
}
}
}
return this;
/**
* Debug fonts loading
*/
// if (ENV.IS_DEV) {
// console.group('Eager fonts loaded!', eagerFonts.length, '/', document.fonts.size);
// console.group('State of eager fonts:');
// eagerFonts.forEach(font => console.log(font.family, font.style, font.weight, font.status));
// console.groupEnd();
// console.group('State of all fonts:');
// document.fonts.forEach(font => console.log(font.family, font.style, font.weight, font.status));
// console.groupEnd();
// }
});
}
}
// IIFE for loading the application
// ==========================================================================
(function() {
new App();
$document.triggerHandler({
type: EVENT.INIT_MODULES,
firstBlood: true
});
})();
////////////////
// Global events
////////////////
function bindEvents() {
// Resize event
const resizeEndEvent = new CustomEvent(CUSTOM_EVENT.RESIZE_END)
window.addEventListener(
"resize",
debounce(() => {
window.dispatchEvent(resizeEndEvent)
}, 200, false)
)
window.addEventListener(
"resize",
onResize
)
}
function onResize() {
setViewportSizes()
}
function setViewportSizes() {
// Document styles
const documentStyles = document.documentElement.style;
// Viewport width
const vw = document.body.clientWidth * 0.01;
documentStyles.setProperty('--vw', `${vw}px`);
// Return if browser supports vh, svh, dvh, & lvh
if (ENV.SUPPORTS_VH) {
return
}
// Viewport height
const svh = document.documentElement.clientHeight * 0.01;
documentStyles.setProperty('--svh', `${svh}px`);
const dvh = window.innerHeight * 0.01;
documentStyles.setProperty('--dvh', `${dvh}px`);
if (document.body) {
const fixed = document.createElement('div');
fixed.style.width = '1px';
fixed.style.height = '100vh';
fixed.style.position = 'fixed';
fixed.style.left = '0';
fixed.style.top = '0';
fixed.style.bottom = '0';
fixed.style.visibility = 'hidden';
document.body.appendChild(fixed);
var fixedHeight = fixed.clientHeight;
fixed.remove();
const lvh = fixedHeight * 0.01;
documentStyles.setProperty('--lvh', `${lvh}px`);
}
}
////////////////
// Execute
////////////////
window.addEventListener('load', () => {
const $style = document.getElementById('main-css');
if ($style) {
if ($style.isLoaded) {
init();
} else {
$style.addEventListener('load', init);
}
} else {
console.warn('The "main-css" stylesheet not found');
}
});

65
assets/scripts/config.js Normal file
View File

@@ -0,0 +1,65 @@
/**
* > When using the esBuild API, all `process.env.NODE_ENV` expressions
* > are automatically defined to `"production"` if all minification
* > options are enabled and `"development"` otherwise. This only happens
* > if `process`, `process.env`, and `process.env.NODE_ENV` are not already
* > defined. This substitution is necessary to avoid code crashing instantly
* > (since `process` is a Node API, not a web API).
* > — https://esbuild.github.io/api/#platform
*/
const NODE_ENV = process.env.NODE_ENV
const IS_MOBILE = window.matchMedia('(any-pointer:coarse)').matches
// Main environment variables
const ENV = Object.freeze({
// Node environment
NAME: NODE_ENV,
IS_PROD: NODE_ENV === 'production',
IS_DEV: NODE_ENV === 'development',
// Device
IS_MOBILE,
IS_DESKTOP: !IS_MOBILE,
// Supports
SUPPORTS_VH: (
'CSS' in window
&& 'supports' in window.CSS
&& window.CSS.supports('height: 100svh')
&& window.CSS.supports('height: 100dvh')
&& window.CSS.supports('height: 100lvh')
)
})
// Main CSS classes used within the project
const CSS_CLASS = Object.freeze({
LOADING: 'is-loading',
LOADED: 'is-loaded',
READY: 'is-ready',
FONTS_LOADED: 'fonts-loaded',
LAZY_CONTAINER: 'c-lazy',
LAZY_LOADED: '-lazy-loaded',
// ...
})
// Custom js events
const CUSTOM_EVENT = Object.freeze({
RESIZE_END: 'loco.resizeEnd',
// ...
})
// Fonts parameters
const FONT = Object.freeze({
EAGER: [
{ family: 'Source Sans', style: 'normal', weight: 400 },
{ family: 'Source Sans', style: 'normal', weight: 700 },
],
})
export {
ENV,
CSS_CLASS,
CUSTOM_EVENT,
FONT,
}

View File

@@ -1,10 +1,23 @@
import TransitionManager from './transitions/TransitionManager';
import svg4everybody from 'svg4everybody';
import { ENV } from './config';
export default function(firstBlood) {
// Dynamic imports for development mode only
let gridHelper;
(async () => {
if (ENV.IS_DEV) {
const gridHelperModule = await import('./utils/grid-helper');
gridHelper = gridHelperModule?.gridHelper;
}
})();
export default function () {
/**
* Use external SVG spritemaps
*/
svg4everybody();
if (firstBlood) {
const transitionManager = new TransitionManager();
}
/**
* Add grid helper
*/
gridHelper?.();
}

View File

@@ -1,2 +1,3 @@
export {default as Example} from './modules/Example';
export {default as Load} from './modules/Load';
export {default as Scroll} from './modules/Scroll';

View File

@@ -1,24 +0,0 @@
let uid = 0;
/**
* Abstract Module
*/
export default class {
constructor(options) {
this.$el = options.$el || null;
this.el = options.el || null;
// Generate a unique module identifier
this.uid = 'm-' + uid++;
// Use jQuery's data API to "store it in the DOM"
this.$el.data('uid', this.uid);
}
init() {}
destroy() {
if (this.$el) {
this.$el.removeData('uid')
}
}
}

View File

@@ -1,30 +1,17 @@
import { APP_NAME } from '../utils/environment';
import AbstractModule from './AbstractModule';
const MODULE_NAME = 'Example';
const EVENT_NAMESPACE = `${APP_NAME}.${MODULE_NAME}`;
const EVENT = {
CLICK: `click.${EVENT_NAMESPACE}`
};
export default class extends AbstractModule {
constructor(options) {
super(options);
// Declaration of properties
console.log('🔨 [module]:constructor - Example');
import { module } from 'modujs';
import { FONT } from '../config';
import { whenReady } from '../utils/fonts';
export default class extends module {
constructor(m) {
super(m);
}
init() {
// Set events and such
whenReady(FONT.EAGER).then((fonts) => this.onFontsLoaded(fonts));
}
destroy() {
console.log('❌ [module]:destroy - Example');
super.destroy();
this.$el.off(`.${EVENT_NAMESPACE}`);
onFontsLoaded(fonts) {
console.log('Example: Eager Fonts Loaded!', fonts)
}
}

View File

@@ -0,0 +1,22 @@
import { module } from 'modujs';
import modularLoad from 'modularload';
export default class extends module {
constructor(m) {
super(m);
}
init() {
const load = new modularLoad({
enterDelay: 0,
transitions: {
customTransition: {}
}
});
load.on('loaded', (transition, oldContainer, newContainer) => {
this.call('destroy', oldContainer, 'app');
this.call('update', newContainer, 'app');
});
}
}

View File

@@ -1,31 +1,59 @@
import { APP_NAME, $document } from '../utils/environment';
import AbstractModule from './AbstractModule';
import ScrollManager from '../scroll/vendors/ScrollManager';
import { module } from 'modujs'
import { lazyLoadImage } from '../utils/image'
import LocomotiveScroll from 'locomotive-scroll'
const MODULE_NAME = 'Scroll';
const EVENT_NAMESPACE = `${APP_NAME}.${MODULE_NAME}`;
export default class extends AbstractModule {
constructor(options) {
super(options);
export default class extends module {
constructor(m) {
super(m);
}
init() {
setTimeout(() => {
this.scrollManager = new ScrollManager({
container: this.$el,
selector: '.js-animate',
smooth: false,
smoothMobile: false,
mobileContainer: $document,
getWay: false,
getSpeed: false
});
}, 500);
this.scroll = new LocomotiveScroll({
modularInstance: this,
})
// // Force scroll to top
// if (history.scrollRestoration) {
// history.scrollRestoration = 'manual'
// window.scrollTo(0, 0)
// }
}
/**
* Lazy load the related image.
*
* @see ../utils/image.js
*
* It is recommended to wrap your `<img>` into an element with the
* CSS class name `.c-lazy`. The CSS class name modifier `.-lazy-loaded`
* will be applied on both the image and the parent wrapper.
*
* ```html
* <div class="c-lazy o-ratio u-4:3">
* <img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=1" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
* </div>
* ```
*
* @param {LocomotiveScroll} args - The Locomotive Scroll instance.
*/
lazyLoad(args) {
lazyLoadImage(args.target, null, () => {
//callback
})
}
scrollTo(params) {
let { target, ...options } = params
options = Object.assign({
// Defaults
duration: 1,
}, options)
this.scroll?.scrollTo(target, options)
}
destroy() {
super.destroy();
this.scrollManager.destroy();
this.scroll.destroy();
}
}

View File

@@ -1,26 +0,0 @@
// ==========================================================================
// Extended Locomotive Scroll
// ==========================================================================
/* jshint esnext: true */
import Scroll, { EVENT_KEY as VENDOR_EVENT_KEY, EVENT as VENDOR_EVENTS, DEFAULTS as VENDOR_DEFAULTS } from './vendors/Scroll'
/**
* UNCOMMENT ONLY THE LINES YOU NEED
*/
// import { $window, $document } from '../../utils/environment';
// import debounce from '../../utils/debounce';
// import { isNumeric } from '../../utils/is';
export const EVENT_KEY = VENDOR_EVENT_KEY;
export const EVENT = Object.assign(VENDOR_EVENTS, {
// TEST: `test.${EVENT_KEY}`
});
export const DEFAULTS = Object.assign(VENDOR_DEFAULTS, { });
export default class extends Scroll {
constructor(options) {
super(options)
}
}

View File

@@ -1,21 +0,0 @@
// ==========================================================================
// Extended Locomotive Smooth Scroll
// ==========================================================================
/* jshint esnext: true */
import SmoothScroll from './vendors/SmoothScroll'
/**
* UNCOMMENT ONLY THE LINES YOU NEED
*/
// import { $window, $document, $html } from '../utils/environment';
// import Scroll, { DEFAULTS, EVENT } from './Scroll';
// import debounce from '../utils/debounce';
// import Scrollbar from 'smooth-scrollbar';
// import { isNumeric } from '../utils/is';
export default class extends SmoothScroll {
constructor(options) {
super(options)
}
}

View File

@@ -1,75 +0,0 @@
import { APP_NAME, $document, $html, $body, isDebug, $pjaxWrapper } from '../utils/environment';
import { EVENT as TransitionEvent } from './TransitionManager'
export default class {
constructor(options) {
this.options = options;
this.wrapper = options.wrapper;
this.overrideClass = options.overrideClass ? options.overrideClass : '';
this.clickedLink = options.clickedLink;
}
launch() {
if(isDebug) {
console.log("---- Launch transition 👊 -----");
}
$html
.removeClass('has-dom-loaded has-dom-animated ')
.addClass(`has-dom-loading ${this.overrideClass}`);
}
hideView(oldView, newView) {
if(isDebug) {
console.log('----- ❌ [VIEW]:hide - ', oldView.getAttribute('data-template'));
}
// launch it at the end (animations...)
$document.triggerHandler({
type:TransitionEvent.READYTOAPPEND,
oldView: oldView,
newView: newView
});
}
displayView(view) {
if(isDebug) {
console.log('----- ✅ [VIEW]:display :', view.getAttribute('data-template'));
}
$html.attr('data-template', view.getAttribute('data-template'));
setTimeout(() => {
$html
.addClass('has-dom-loaded')
.removeClass('has-dom-loading');
setTimeout(() => {
$html
.removeClass(this.overrideClass)
.addClass('has-dom-animated');
}, 1000);
// launch it at the end (animations...)
$document.triggerHandler({
type:TransitionEvent.READYTODESTROY
});
},1000);
}
destroy() {
if(isDebug) {
console.log("---- ❌ [transition]:destroy -----");
}
}
}

View File

@@ -1,13 +0,0 @@
import { APP_NAME, $document, $html, isDebug, $pjaxWrapper } from '../utils/environment';
import BaseTransition from './BaseTransition';
import { EVENT as TransitionEvent } from './TransitionManager'
export default class extends BaseTransition{
constructor(options) {
super(options);
this.overrideClass = '-custom-transition';
}
}

View File

@@ -1,256 +0,0 @@
import Pjax from 'pjax';
import { APP_NAME, $document, $html, isDebug, $pjaxWrapper, $window } from '../utils/environment';
import { EVENT as APP_EVENT } from '../app';
//List here all of your transitions
import * as transitions from './transitions';
const MODULE_NAME = 'Transition';
const EVENT_NAMESPACE = `${APP_NAME}.${MODULE_NAME}`;
export const EVENT = {
CLICK: `click.${EVENT_NAMESPACE}`,
READYTOAPPEND: `readyToAppend.${EVENT_NAMESPACE}`,
READYTODESTROY: `readyToDestroy.${EVENT_NAMESPACE}`,
GOTO: `goto.${EVENT_NAMESPACE}`
};
/*
@todo :
- ✅ get data-transition on clicked link -> launch() and add switch(){}
- ✅ add goto listener
- ✅ add overrideClass system for all transitions
- ✅ add base class manager like old DefaultTransition (has-dom-loaded, has-dom-loading etc..)
======= SCHEMA =======
[] : listener
* : trigger event
[pjax:send] -> (transition) launch()
[pjax:switch] (= new view is loaded) -> (transition) hideView()-> hide animations & *readyToAppend
[readyToAppend] -> append() -> delete modules
-> remove oldView from the DOM, and innerHTMl newView
-> change()
display() -> (transition) displayView() -> display animations & *readyToDestroy
-> init new modules
[readyToAppend] -> reinit()
*/
export default class {
constructor() {
// jQuery ondomready
$window.on('load',() => {
this.load();
});
this.transition = new transitions['BaseTransition']({
wrapper: this.wrapper
});
/*
===== PJAX CONFIGURATION =====
*/
this.containerClass = '.js-pjax-container';
this.wrapperId = 'js-pjax-wrapper';
this.noPjaxRequestClass = 'no-transition';
this.wrapper = document.getElementById(this.wrapperId);
this.options = {
debug: false,
cacheBust: false,
elements: [`a:not(.${this.noPjaxRequestClass})`,'form[action]'],
selectors: ['title',`${this.containerClass}`],
switches: {},
requestOptions: {
timeout: 2000
}
};
this.options.switches[this.containerClass] = (oldEl, newEl, options) => this.switch(oldEl, newEl, options)
this.pjax = new Pjax(this.options);
/*
===== LISTENERS =====
*/
document.addEventListener('pjax:send',(e) => this.send(e));
$document.on(EVENT.READYTOAPPEND,(event) => {
this.append(event.oldView, event.newView);
});
$document.on(EVENT.READYTODESTROY,(event) => {
this.reinit();
});
/** goto exampe
$document.triggerHandler({
type: 'goto.Transition',
options : {
el: {{element clicked?}},
link: {{url}}
}
});
*/
$document.on(EVENT.GOTO, (e) => {
if(e.options.el != undefined) {
this.autoEl = e.options.el.get(0);
}
this.pjax.loadUrl(e.options.link, $.extend({}, this.pjax.options));
});
}
/**
* (PJAX) Launch when pjax receive a request
* get & manage data-transition,init and launch it
* @param {event}
* @return void
*/
send(e) {
if(isDebug) {
console.log("---- Launch request 🙌 -----");
}
let el,transition;
if(e.triggerElement != undefined) {
el = e.triggerElement;
transition = el.getAttribute('data-transition') ? el.getAttribute('data-transition') : 'BaseTransition';
$html.attr('data-transition',transition);
} else {
if (this.autoEl != undefined) {
el = this.autoEl;
} else {
el = document;
}
transition = 'BaseTransition';
}
// options available : wrapper, overrideClass
this.transition = new transitions[transition]({
wrapper: this.wrapper,
clickedLink: el
});
this.transition.launch();
}
/**
* (PJAX) Launch when new page is loaded
* @param {js dom element},
* @param {js dom element}
* @param {options : pjax options}
* @return void
*/
switch(oldView, newView, options) {
if(isDebug) {
console.log('---- Next view loaded 👌 -----');
}
this.transition.hideView(oldView, newView);
}
/**
* Launch when you trigger EVENT.READYTOAPPEND in your transition
* after newView append, launch this.change()
* @param {js dom element},
* @param {js dom element}
* @return void
*/
append(oldView, newView) {
newView.style.opacity = 0;
this.wrapper.appendChild(newView);
// Add these 2 rAF if you want to have the containers overlapped
// Useful with a image transition, to prevent flickering
// requestAnimationFrame(() => {
// requestAnimationFrame(() => {
newView.style.opacity = 1;
this.change(oldView, newView);
// });
// });
}
/**
* launch after this.append(), remove modules, remove oldView and set the newView
* @param {js dom element},
* @return void
*/
change(oldView, newView) {
$document.triggerHandler({
type: APP_EVENT.DELETE_SCOPED_MODULES,
$scope: $pjaxWrapper
});
this.wrapper.innerHTML = newView.outerHTML;
oldView.remove();
// Fetch any inline script elements.
const scripts = newView.querySelectorAll('script.js-inline');
if (scripts instanceof window.NodeList) {
let i = 0;
let len = scripts.length;
for (; i < len; i++) {
eval(scripts[i].innerHTML);
}
}
$document.triggerHandler({
type: APP_EVENT.INIT_SCOPED_MODULES,
isPjax: true
});
this.pjax.onSwitch();
this.transition.displayView(newView);
}
/**
* Launch when you trigger EVENT.READYTODESTROY in your transition -> displayView(), at the end
* @return void
*/
reinit() {
this.transition.destroy();
$html.attr('data-transition','');
this.transition = new transitions['BaseTransition']({
wrapper: this.wrapper
});
}
/**
* DOM is loaded
*
* @return {void}
*/
load() {
$html.addClass('has-dom-loaded');
$html.removeClass('has-dom-loading');
setTimeout(() => {
$html.addClass('has-dom-animated');
}, 1000)
}
}

View File

@@ -1,2 +0,0 @@
export {default as BaseTransition} from './BaseTransition';
export {default as CustomTransition} from './CustomTransition';

View File

@@ -1,88 +0,0 @@
import { isArray } from './is';
export function addToArray ( array, value ) {
const index = array.indexOf( value );
if ( index === -1 ) {
array.push( value );
}
}
export function arrayContains ( array, value ) {
for ( let i = 0, c = array.length; i < c; i++ ) {
if ( array[i] == value ) {
return true;
}
}
return false;
}
export function arrayContentsMatch ( a, b ) {
let i;
if ( !isArray( a ) || !isArray( b ) ) {
return false;
}
if ( a.length !== b.length ) {
return false;
}
i = a.length;
while ( i-- ) {
if ( a[i] !== b[i] ) {
return false;
}
}
return true;
}
export function ensureArray ( x ) {
if ( typeof x === 'string' ) {
return [ x ];
}
if ( x === undefined ) {
return [];
}
return x;
}
export function lastItem ( array ) {
return array[ array.length - 1 ];
}
export function removeFromArray ( array, member ) {
if ( !array ) {
return;
}
const index = array.indexOf( member );
if ( index !== -1 ) {
array.splice( index, 1 );
}
}
export function toArray ( arrayLike ) {
const array = [];
let i = arrayLike.length;
while ( i-- ) {
array[i] = arrayLike[i];
}
return array;
}
export function findByKeyValue( array, key, value ) {
return array.filter(function( obj ) {
return obj[key] === value;
});
}
export function cloneArray( array ) {
return JSON.parse(JSON.stringify(array));
}

View File

@@ -1,15 +0,0 @@
export default function(func, wait, immediate) {
let timeout;
return function() {
const context = this;
const args = arguments;
const later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}

View File

@@ -0,0 +1,7 @@
const $html = document.documentElement
const $body = document.body
export {
$html,
$body,
}

View File

@@ -1,12 +0,0 @@
const APP_NAME = 'Boilerplate';
const DATA_API_KEY = '.data-api';
const $document = $(document);
const $window = $(window);
const $html = $(document.documentElement).removeClass('has-no-js').addClass('has-js');
const $body = $(document.body);
const $pjaxWrapper = $('#js-pjax-wrapper');
const isDebug = !!$html.data('debug');
export { APP_NAME, DATA_API_KEY, $document, $window, $html, $body, isDebug, $pjaxWrapper };

View File

@@ -0,0 +1,402 @@
/**
* Font Faces
*
* Provides utilities to facilitate interactions with the CSS Font Loading API.
*
* Features functions to:
*
* - Retrieve one or more `FontFace` instances based on a font search query.
* - Check if a `FontFace` instance matches a font search query.
* - Eagerly load fonts that match a font search query.
* - Wait until fonts that match a font search query are loaded.
*
* References:
*
* - {@link https://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API}
*/
/**
* @typedef {Object} FontFaceReference
*
* @property {string} family - The name used to identify the font in our CSS.
* @property {string} [style] - The style used by the font in our CSS.
* @property {string} [weight] - The weight used by the font in our CSS.
*/
const isFontLoadingAPIAvailable = ('fonts' in document);
/**
* Determines if the given font matches the given `FontFaceReference`.
*
* @param {FontFace} font - The font to inspect.
* @param {FontFaceReference} criterion - The object of property values to match.
*
* @returns {boolean}
*/
function conformsToReference(font, criterion)
{
for (const [ key, value ] of Object.entries(criterion)) {
switch (key) {
case 'family': {
if (trim(font[key]) !== value) {
return false;
}
break;
}
case 'weight': {
/**
* Note concerning font weights:
* Loose equality (`==`) is used to compare numeric weights,
* a number (`400`) and a numeric string (`"400"`).
* Comparison between numeric and keyword values is neglected.
*
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#common_weight_name_mapping
*/
if (font[key] != value) {
return false;
}
break;
}
default: {
if (font[key] !== value) {
return false;
}
break;
}
}
}
return true;
}
/**
* Determines if the given font matches the given font shorthand.
*
* @param {FontFace} font - The font to inspect.
* @param {string} criterion - The font shorthand to match.
*
* @returns {boolean}
*/
function conformsToShorthand(font, criterion)
{
const family = trim(font.family);
if (trim(family) === criterion) {
return true;
}
if (
criterion.endsWith(trim(family)) && (
criterion.match(font.weight) ||
criterion.match(font.style)
)
) {
return true;
}
return true;
}
/**
* Determines if the given font matches any of the given criteria.
*
* @param {FontFace} font - The font to inspect.
* @param {FontFaceReference[]} criteria - A list of objects with property values to match.
*
* @returns {boolean}
*/
function conformsToAnyReference(font, criteria)
{
for (const criterion of criteria) {
if (conformsToReference(font, criterion)) {
return true;
}
}
return false;
}
/**
* Returns an iterator of all `FontFace` from `document.fonts` that satisfy
* the provided `FontFaceReference`.
*
* @param {FontFaceReference} font
*
* @returns {FontFace[]}
*/
function findManyByReference(search)
{
const found = [];
for (const font of document.fonts) {
if (conformsToReference(font, search)) {
found.push(font);
}
}
return found;
}
/**
* Returns an iterator of all `FontFace` from `document.fonts` that satisfy
* the provided font shorthand.
*
* @param {string} font
*
* @returns {FontFace[]}
*/
function findManyByShorthand(search)
{
const found = [];
for (const font of document.fonts) {
if (conformsToShorthand(font, search)) {
found.push(font);
}
}
return found;
}
/**
* Returns the first `FontFace` from `document.fonts` that satisfies
* the provided `FontFaceReference`.
*
* @param {FontFaceReference} font
*
* @returns {?FontFace}
*/
function findOneByReference(search)
{
for (const font of document.fonts) {
if (conformsToReference(font, criterion)) {
return font;
}
}
return null;
}
/**
* Returns the first `FontFace` from `document.fonts` that satisfies
* the provided font shorthand.
*
* Examples:
*
* - "Roboto"
* - "italic bold 16px Roboto"
*
* @param {string} font
*
* @returns {?FontFace}
*/
function findOneByShorthand(search)
{
for (const font of document.fonts) {
if (conformsToShorthand(font, search)) {
return font;
}
}
return null;
}
/**
* Returns a `FontFace` from `document.fonts` that satisfies
* the provided query.
*
* @param {FontFaceReference|string} font - Either:
* - a `FontFaceReference` object
* - a font family name
* - a font specification, for example "italic bold 16px Roboto"
*
* @returns {?FontFace}
*
* @throws {TypeError}
*/
function getAny(search) {
if (search) {
switch (typeof search) {
case 'string':
return findOneByShorthand(search);
case 'object':
return findOneByReference(search);
}
}
throw new TypeError(
'Expected font query to be font shorthand or font reference'
);
}
/**
* Returns an iterator of all `FontFace` from `document.fonts` that satisfy
* the provided queries.
*
* @param {FontFaceReference|string|(FontFaceReference|string)[]} queries
*
* @returns {FontFace[]}
*
* @throws {TypeError}
*/
function getMany(queries) {
if (!Array.isArray(queries)) {
queries = [ queries ];
}
const found = new Set();
queries.forEach((search) => {
if (search) {
switch (typeof search) {
case 'string':
found.add(...findManyByShorthand(search));
return;
case 'object':
found.add(...findManyByReference(search));
return;
}
}
throw new TypeError(
'Expected font query to be font shorthand or font reference'
);
})
return [ ...found ];
}
/**
* Determines if a font face is registered.
*
* @param {FontFace|FontFaceReference|string} search - Either:
* - a `FontFace` instance
* - a `FontFaceReference` object
* - a font family name
* - a font specification, for example "italic bold 16px Roboto"
*
* @returns {boolean}
*/
function hasAny(search) {
if (search instanceof FontFace) {
return document.fonts.has(search);
}
return getAny(search) != null;
}
/**
* Eagerly load fonts.
*
* Most user agents only fetch and load fonts when they are first needed
* ("lazy loaded"), which can result in a perceptible delay.
*
* This function will "eager load" the fonts.
*
* @param {(FontFace|FontFaceReference)[]} fontsToLoad - List of fonts to load.
* @param {boolean} [debug] - If TRUE, log details to the console.
*
* @returns {Promise}
*/
async function loadFonts(fontsToLoad, debug = false)
{
if ((fontsToLoad.size ?? fontsToLoad.length) === 0) {
throw new TypeError(
'Expected at least one font'
);
}
return await loadFontsWithAPI([ ...fontsToLoad ], debug);
}
/**
* Eagerly load a font using `FontFaceSet` API.
*
* @param {FontFace} font
*
* @returns {Promise}
*/
async function loadFontFaceWithAPI(font)
{
return await (font.status === 'unloaded'
? font.load()
: font.loaded
).then((font) => font, (err) => font)
}
/**
* Eagerly load fonts using `FontFaceSet` API.
*
* @param {FontFaceReference[]} fontsToLoad
* @param {boolean} [debug]
*
* @returns {Promise}
*/
async function loadFontsWithAPI(fontsToLoad, debug = false)
{
debug && console.group('[loadFonts:API]', fontsToLoad.length, '/', document.fonts.size);
const fontsToBeLoaded = [];
for (const fontToLoad of fontsToLoad) {
if (fontToLoad instanceof FontFace) {
if (!document.fonts.has(fontToLoad)) {
document.fonts.add(fontToLoad);
}
fontsToBeLoaded.push(
loadFontFaceWithAPI(fontToLoad)
);
} else {
fontsToBeLoaded.push(
...getMany(fontToLoad).map((font) => loadFontFaceWithAPI(font))
);
}
}
debug && console.groupEnd();
return await Promise.all(fontsToBeLoaded);
}
/**
* Removes quotes from the the string.
*
* When a `@font-face` is declared, the font family is sometimes
* defined in quotes which end up included in the `FontFace` instance.
*
* @param {string} value
*
* @returns {string}
*/
function trim(value) {
return value.replace(/['"]+/g, '');
}
/**
* Returns a Promise that resolves with the specified fonts
* when they are done loading or failed.
*
* @param {FontFaceReference|string|(FontFaceReference|string)[]} queries
*
* @returns {Promise}
*/
async function whenReady(queries)
{
const fonts = getMany(queries);
return await Promise.all(fonts.map((font) => font.loaded));
}
export {
getAny,
getMany,
hasAny,
isFontLoadingAPIAvailable,
loadFonts,
whenReady,
}

View File

@@ -0,0 +1,138 @@
/**
* Grid Helper
*
* Provides a grid based on the design guidelines and is helpful for web integration.
*
* - `Control + g` to toggle the grid
*
*/
/**
* @typedef {Object} GridHelperReference
*
* @property {string} [gutterCssVar=GRID_HELPER_GUTTER_CSS_VAR] - CSS variable used to define grid gutters.
* @property {string} [marginCssVar=GRID_HELPER_MARGIN_CSS_VAR] - CSS variable used to define grid margins.
* @property {string} [rgbaColor=GRID_HELPER_RGBA_COLOR] - RGBA color for the grid appearence.
*/
const GRID_HELPER_GUTTER_CSS_VAR = '--grid-gutter';
const GRID_HELPER_MARGIN_CSS_VAR = '--grid-margin';
const GRID_HELPER_RGBA_COLOR = 'rgba(255, 0, 0, .1)';
/**
* Create a grid helper
*
* @param {GridHelperReference}
*
*/
function gridHelper({
gutterCssVar = GRID_HELPER_GUTTER_CSS_VAR,
marginCssVar = GRID_HELPER_MARGIN_CSS_VAR,
rgbaColor = GRID_HELPER_RGBA_COLOR,
} = {}) {
// Set grid container
const $gridContainer = document.createElement('div');
document.body.append($gridContainer);
// Set grid appearence
setGridHelperColumns($gridContainer, rgbaColor);
setGridHelperStyles($gridContainer, gutterCssVar, marginCssVar);
// Set grid interactivity
setGridEvents($gridContainer, rgbaColor);
}
/**
* Set grid container styles
*
* @param {HTMLElement} $container - DOM Element that contains a list of generated columns
* @param {string} gutterCssVar - CSS variable used to define grid gutters.
* @param {string} marginCssVar - CSS variable used to define grid margins.
*
*/
function setGridHelperStyles($container, gutterCssVar, marginCssVar) {
const elStyles = $container.style;
elStyles.zIndex = '10000';
elStyles.position = 'fixed';
elStyles.top = '0';
elStyles.left = '0';
elStyles.display = 'flex';
elStyles.width = '100%';
elStyles.height = '100%';
elStyles.columnGap = `var(${gutterCssVar}, 0)`;
elStyles.paddingLeft = `var(${marginCssVar}, 0)`;
elStyles.paddingRight = `var(${marginCssVar}, 0)`;
elStyles.pointerEvents = 'none';
elStyles.visibility = 'hidden';
}
/**
* Set grid columns
*
* @param {HTMLElement} $container - DOM Element that will contain a list of generated columns
* @param {string} rgbaColor - RGBA color to stylize the generated columns
*
*/
function setGridHelperColumns($container, rgbaColor) {
// Clear columns
$container.innerHTML = '';
// Loop through columns
const columns = Number(
window.getComputedStyle($container).getPropertyValue('--grid-columns')
);
let $col;
for (var i = 0; i < columns; i++) {
$col = document.createElement('div');
$col.style.flex = '1 1 0';
$col.style.backgroundColor = rgbaColor;
$container.appendChild($col);
}
}
/**
* Set grid events
*
* Resize to rebuild columns
* Keydown/Keyup to toggle the grid display
*
* @param {HTMLElement} $container - DOM Element that contains a list of generated columns
* @param {string} rgbaColor - RGBA color to stylize the generated columns
*
*/
function setGridEvents($container, rgbaColor) {
// Handle resize
window.addEventListener(
'resize',
setGridHelperColumns($container, rgbaColor)
);
// Toggle grid
let ctrlDown = false;
let isActive = false;
document.addEventListener('keydown', (e) => {
if (e.key == 'Control') {
ctrlDown = true;
} else {
if (ctrlDown && e.key == 'g') {
if (isActive) {
$container.style.visibility = 'hidden';
} else {
$container.style.visibility = 'visible';
}
isActive = !isActive;
}
}
});
document.addEventListener('keyup', (e) => {
if (e.key == 'Control') {
ctrlDown = false;
}
});
}
export { gridHelper };

View File

@@ -1,96 +1,140 @@
/**
* @see https://github.com/ractivejs/ractive/blob/dev/src/utils/html.js
* Escape HTML string
* @param {string} str - string to escape
* @return {string} escaped string
*/
export function escapeHtml(str) {
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
const escapeHtml = str =>
str.replace(/[&<>'"]/g, tag => ({
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&#39;',
'"': '&quot;'
}[tag]))
/**
* Prepare HTML content that contains mustache characters for use with Ractive
* @param {string} str
* @return {string}
* Unescape HTML string
* @param {string} str - string to unescape
* @return {string} unescaped string
*/
export function unescapeHtml(str) {
return str
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&');
}
const unescapeHtml = str =>
str.replace('&amp;', '&')
.replace('&lt;', '<')
.replace('&gt;', '>')
.replace('&#39;', "'")
.replace('&quot;', '"')
/**
* Get element data attributes
* @param {DOMElement} node
* @return {Array} data
* @param {HTMLElement} node - node element
* @return {array} node data
*/
export function getNodeData(node) {
const getNodeData = node => {
// All attributes
const attributes = node.attributes;
const attributes = node.attributes
// Regex Pattern
const pattern = /^data\-(.+)$/;
const pattern = /^data\-(.+)$/
// Output
const data = {};
const data = {}
for (let i in attributes) {
if (!attributes[i]) {
continue;
continue
}
// Attributes name (ex: data-module)
let name = attributes[i].name;
let name = attributes[i].name
// This happens.
if (!name) {
continue;
continue
}
let match = name.match(pattern);
let match = name.match(pattern)
if (!match) {
continue;
continue
}
// If this throws an error, you have some
// serious problems in your HTML.
data[match[1]] = getData(node.getAttribute(name));
data[match[1]] = getData(node.getAttribute(name))
}
return data;
}
const rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/;
/**
* Parse value to data type.
*
* @link https://github.com/jquery/jquery/blob/3.1.1/src/data.js
* @param {string} data - A value to convert.
* @return {mixed} Returns the value in its natural data type.
* @param {string} data - value to convert
* @return {mixed} value in its natural data type
*/
export function getData(data) {
const rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/
const getData = data => {
if (data === 'true') {
return true;
return true
}
if (data === 'false') {
return false;
return false
}
if (data === 'null') {
return null;
return null
}
// Only convert to a number if it doesn't change the string
if (data === +data+'') {
return +data;
return +data
}
if (rbrace.test( data )) {
return JSON.parse( data );
if (rbrace.test(data)) {
return JSON.parse(data)
}
return data;
return data
}
/**
* Returns an array containing all the parent nodes of the given node
* @param {HTMLElement} $el - DOM Element
* @return {array} parent nodes
*/
const getParents = $el => {
// Set up a parent array
let parents = []
// Push each parent element to the array
for (; $el && $el !== document; $el = $el.parentNode) {
parents.push($el)
}
// Return our parent array
return parents
}
export {
escapeHtml,
unescapeHtml,
getNodeData,
getData,
getParents,
}

View File

@@ -0,0 +1,112 @@
import { CSS_CLASS } from '../config'
/**
* Get an image meta data
*
* @param {HTMLImageElement} $img - The image element.
* @return {object} The given image meta data
*/
const getImageMetadata = $img => ({
url: $img.src,
width: $img.naturalWidth,
height: $img.naturalHeight,
ratio: $img.naturalWidth / $img.naturalHeight,
})
/**
* Load the given image.
*
* @param {string} url - The URI to lazy load into $el.
* @param {object} options - An object of options
* @return {void}
*/
const loadImage = (url, options = {}) => {
return new Promise((resolve, reject) => {
const $img = new Image()
if (options.crossOrigin) {
$img.crossOrigin = options.crossOrigin
}
const loadCallback = () => {
resolve({
element: $img,
...getImageMetadata($img),
})
}
if($img.decode) {
$img.src = url
$img.decode().then(loadCallback).catch(e => {
reject(e)
})
} else {
$img.onload = loadCallback
$img.onerror = (e) => {
reject(e)
}
$img.src = url
}
})
}
/**
* Lazy load the given image.
*
* @param {HTMLImageElement} $el - The image element.
* @param {?string} url - The URI to lazy load into $el.
* If falsey, the value of the `data-src` attribute on $el will be used as the URI.
* @param {?function} callback - A function to call when the image is loaded.
* @return {void}
*/
const LAZY_LOADED_IMAGES = []
const lazyLoadImage = async ($el, url, callback) => {
let src = url ? url : $el.dataset.src
let loadedImage = LAZY_LOADED_IMAGES.find(image => image.url === src)
if (!loadedImage) {
loadedImage = await loadImage(src)
if (!loadedImage.url) {
return
}
LAZY_LOADED_IMAGES.push(loadedImage)
}
if($el.src === src) {
return
}
if ($el.tagName === 'IMG') {
$el.src = loadedImage.url
} else {
$el.style.backgroundImage = `url(${loadedImage.url})`
}
requestAnimationFrame(() => {
let lazyParent = $el.closest(`.${CSS_CLASS.LAZY_CONTAINER}`)
if(lazyParent) {
lazyParent.classList.add(CSS_CLASS.LAZY_LOADED)
lazyParent.style.backgroundImage = ''
}
$el.classList.add(CSS_CLASS.LAZY_LOADED)
callback?.()
})
}
export {
getImageMetadata,
loadImage,
lazyLoadImage
}

View File

@@ -1,37 +1,25 @@
const toString = Object.prototype.toString;
const arrayLikePattern = /^\[object (?:Array|FileList)\]$/;
/**
* Determines if the argument is object-like.
*
* A value is object-like if it's not `null` and has a `typeof` result of "object".
*
* @param {*} x - The value to be checked.
* @return {boolean}
*/
// thanks, http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
export function isArray ( thing ) {
return toString.call( thing ) === '[object Array]';
}
export function isArrayLike ( obj ) {
return arrayLikePattern.test( toString.call( obj ) );
}
export function isEqual ( a, b ) {
if ( a === null && b === null ) {
return true;
}
if ( typeof a === 'object' || typeof b === 'object' ) {
return false;
}
return a === b;
}
// http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
export function isNumeric ( thing ) {
return !isNaN( parseFloat( thing ) ) && isFinite( thing );
}
export function isObject ( thing ) {
return ( thing && toString.call( thing ) === '[object Object]' );
}
export function isFunction( thing ) {
const getType = {};
return thing && getType.toString.call(thing) === '[object Function]';
const isObject = x => (x && typeof x === 'object')
/**
* Determines if the argument is a function.
*
* @param {*} x - The value to be checked.
* @return {boolean}
*/
const isFunction = x => typeof x === 'function'
export {
isObject,
isFunction
}

View File

@@ -0,0 +1,54 @@
/**
* Clamp value
* @param {number} min - start value
* @param {number} max - end value
* @param {number} a - alpha value
* @return {number} clamped value
*/
const clamp = (min = 0, max = 1, a) => Math.min(max, Math.max(min, a))
/**
* Calculate lerp
* @param {number} x - start value
* @param {number} y - end value
* @param {number} a - alpha value
* @return {number} lerp value
*/
const lerp = (x, y, a) => x * (1 - a) + y * a
/**
* Calculate inverted lerp
* @param {number} x - start value
* @param {number} y - end value
* @param {number} a - alpha value
* @return {number} inverted lerp value
*/
const invlerp = (x, y, a) => clamp((a - x)/(y - x))
/**
* Round number to the specified precision.
*
* This function is necessary because `Number.prototype.toPrecision()`
* and `Number.prototype.toFixed()`
*
* @param {number} number - The floating point number to round.
* @param {number} [precision] - The number of digits to appear after the decimal point.
* @return {number} The rounded number.
*/
const roundNumber = (number, precision = 2) => {
return Number.parseFloat(number.toPrecision(precision));
}
export {
clamp,
lerp,
invlerp,
roundNumber
}

View File

@@ -1,63 +0,0 @@
import { isNumeric } from './is'
let isAnimating = false;
const defaults = {
easing: 'swing',
headerOffset: 60,
speed: 300
};
/**
* scrollTo is a function that scrolls a container to an element's position within that controller
* Uses jQuery's $.Deferred to allow using a callback on animation completion
* @param {object} $element A jQuery node
* @param {object} options
*/
export function scrollTo($element, options) {
const deferred = $.Deferred();
// Drop everything if this ain't a jQuery object
if ($element instanceof jQuery && $element.length > 0) {
// Merging options
options = $.extend({}, defaults, (typeof options !== 'undefined' ? options : {}));
// Prevents accumulation of animations
if (isAnimating === false) {
isAnimating = true;
// Default container that we'll be scrolling
let $container = $('html, body');
let elementOffset = 0;
// Testing container in options for jQuery-ness
// If we're not using a custom container, we take the top document offset
// If we are, we use the elements position relative to the container
if (typeof options.$container !== 'undefined' && options.$container instanceof jQuery && options.$container.length > 0) {
$container = options.$container;
if (typeof options.scrollTop !== 'undefined' && isNumeric(options.scrollTop) && options.scrollTop !== 0) {
scrollTop = options.scrollTop;
} else {
scrollTop = $element.position().top - options.headerOffset;
}
} else {
if (typeof options.scrollTop !== 'undefined' && isNumeric(options.scrollTop) && options.scrollTop !== 0) {
scrollTop = options.scrollTop;
} else {
scrollTop = $element.offset().top - options.headerOffset;
}
}
$container.animate({
scrollTop: scrollTop
}, options.speed, options.easing, function() {
isAnimating = false;
deferred.resolve();
});
}
}
return deferred.promise();
}

View File

@@ -0,0 +1,78 @@
/**
* Creates a debounced function.
*
* A debounced function delays invoking `callback` until after
* `delay` milliseconds have elapsed since the last time the
* debounced function was invoked.
*
* Useful for behaviour that should only happen _before_ or
* _after_ an event has stopped occurring.
*
* @template {function} T
*
* @param {T} callback - The function to debounce.
* @param {number} delay - The number of milliseconds to wait.
* @param {boolean} [immediate] -
* If `true`, `callback` is invoked before `delay`.
* If `false`, `callback` is invoked after `delay`.
* @return {function<T>} The new debounced function.
*/
const debounce = (callback, delay, immediate = false) => {
let timeout = null
return (...args) => {
clearTimeout(timeout)
const later = () => {
timeout = null
if (!immediate) {
callback(...args)
}
}
if (immediate && !timeout) {
callback(...args)
}
timeout = setTimeout(later, delay)
}
}
/**
* Creates a throttled function.
*
* A throttled function invokes `callback` at most once per every
* `delay` milliseconds.
*
* Useful for rate-limiting an event that occurs in quick succession.
*
* @template {function} T
*
* @param {T} callback - The function to throttle.
* @param {number} delay - The number of milliseconds to wait.
* @return {function<T>} The new throttled function.
*/
const throttle = (callback, delay) => {
let timeout = false
return (...args) => {
if (!timeout) {
timeout = true
callback(...args)
setTimeout(() => {
timeout = false
}, delay)
}
}
}
export {
debounce,
throttle
}

View File

@@ -0,0 +1,35 @@
/**
* Get translate function
* @param {HTMLElement} $el - DOM Element
* @return {number|object} translate value
*/
const getTranslate = $el => {
if(!window.getComputedStyle) {
return
}
let translate
const style = getComputedStyle($el)
const transform = style.msTransform || style.webkitTransform || style.MozTransform || style.OTransform || style.transform
const matrix3D = transform.match(/^matrix3d\((.+)\)$/)
if(matrix3D) {
translate = parseFloat(matrix3D[1].split(', ')[13])
} else {
const matrix = transform.match(/^matrix\((.+)\)$/)
translate = {
x: matrix ? parseFloat(matrix[1].split(', ')[4]) : 0
y: matrix ? parseFloat(matrix[1].split(', ')[5]) : 0
}
}
return translate
}
export {
transform,
getTranslate
}

View File

@@ -1,129 +1,118 @@
import { isFunction } from './is';
import { arrayContains, findByKeyValue, removeFromArray } from './array';
import { $document, $window, $html, $body } from './environment';
const CALLBACKS = {
hidden: [],
visible: []
};
const ACTIONS = [
'addCallback',
'removeCallback'
];
const STATES = [
'visible',
'hidden'
];
const PREFIX = 'v-';
let UUID = 0;
// Main event
$document.on('visibilitychange', function(event) {
if (document.hidden) {
onDocumentChange('hidden');
} else {
onDocumentChange('visible');
}
});
/**
* Add a callback
* @param {string} state
* @param {function} callback
* @return {string} ident
* The `PageVisibility` interface provides support for dispatching
* a custom event derived from the value of {@see document.visibilityState}
* when the "visibilitychange" event is fired.
*
* The custom events are:
*
* - "visibilityhidden" representing the "hidden" visibility state.
* - "visibilityvisible" representing the "visibile" visibility state.
*
* Example:
*
* ```js
* import pageVisibility from './utils/visibility.js';
*
* pageVisibility.enableCustomEvents();
*
* document.addEventListener('visibilityhidden', () => videoElement.pause());
* ```
*
* The dispatched event object is the same from "visibilitychange"
* and renamed according to the visibility state.
*
* The `PageVisibility` interface does not manage the attachment/detachment
* of event listeners on the custom event types.
*
* Further reading:
*
* - {@link https://www.w3.org/TR/page-visibility/ W3 Specification}
* - {@link https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API MDN Web Docs}
*/
function addCallback (state, options) {
let callback = options.callback || '';
export default new class PageVisibility {
/**
* Checks if the "visibilitychange" event listener has been registered.
*
* @return {boolean} Returns `false` if the event listener is not registered,
* otherwise returns `true`.
*/
get isEnabled() {
return isVisibilityChangeObserved;
}
/**
* Removes the "visibilitychange" event listener.
*
* @return {boolean} Returns `false` if the event listener was already unregistered,
* otherwise returns `true`.
*/
disableCustomEvents() {
if (isVisibilityChangeObserved) {
isVisibilityChangeObserved = false;
document.removeEventListener('visibilitychange', handleCustomVisibilityChange);
return true;
}
if (!isFunction(callback)) {
console.warn('Callback is not a function');
return false;
}
let ident = PREFIX + UUID++;
/**
* Registers the "visibilitychange" event listener.
*
* @return {boolean} Returns `false` if the event listener was already registered,
* otherwise returns `true`.
*/
enableCustomEvents() {
if (!isVisibilityChangeObserved) {
isVisibilityChangeObserved = true;
document.addEventListener('visibilitychange', handleCustomVisibilityChange);
return true;
}
CALLBACKS[state].push({
ident: ident,
callback: callback
});
return ident;
}
/**
* Remove a callback
* @param {string} state Visible or hidden
* @param {string} ident Unique identifier
* @return {boolean} If operation was a success
*/
function removeCallback (state, options) {
let ident = options.ident || '';
if (typeof(ident) === 'undefined' || ident === '') {
console.warn('Need ident to remove callback');
return false;
}
let index = findByKeyValue(CALLBACKS[state], 'ident', ident)[0];
// console.log(ident)
// console.log(CALLBACKS[state])
if (typeof(index) !== 'undefined') {
removeFromArray(CALLBACKS[state], index);
return true;
} else {
console.warn('Callback could not be found');
return false;
}
}
/**
* When document state changes, trigger callbacks
* @param {string} state Visible or hidden
* Tracks whether custom visibility event types
* are available (`true`) or not (`false`).
*
* @type {boolean}
*/
function onDocumentChange (state) {
let callbackArray = CALLBACKS[state];
let i = 0;
let len = callbackArray.length;
let isVisibilityChangeObserved = false;
for (; i < len; i++) {
callbackArray[i].callback();
}
/**
* Dispatches a custom visibility event at the document derived
* from the value of {@see document.visibilityState}.
*
* @listens document#visibilitychange
*
* @fires PageVisibility#visibilityhidden
* @fires PageVisibility#visibilityvisible
*
* @param {Event} event
* @return {void}
*/
function handleCustomVisibilityChange(event) {
document.dispatchEvent(new CustomEvent(`visibility${document.visibilityState}`, {
detail: {
cause: event
}
}));
}
/**
* Public facing API for adding and removing callbacks
* @param {object} options Options
* @return {boolean|integer} Unique identifier for the callback or boolean indicating success or failure
* The "visibilityhidden" eveent is fired at the document when the contents
* of its tab have become hidden.
*
* @event PageVisibility#visibilityhidden
* @type {Event}
*/
function visibilityApi (options) {
let action = options.action || '';
let state = options.state || '';
let ret;
// Type and value checking
if (!arrayContains(ACTIONS, action)) {
console.warn('Action does not exist');
return false;
}
if (!arrayContains(STATES, state)) {
console.warn('State does not exist');
return false;
}
// @todo Magic call function pls
if (action === 'addCallback') {
ret = addCallback(state, options);
} else if (action === 'removeCallback') {
ret = removeCallback(state, options);
}
return ret;
}
export { visibilityApi };
/**
* The "visibilityvisible" eveent is fired at the document when the contents
* of its tab have become visible.
*
* @event PageVisibility#visibilityvisible
* @type {Event}
*/

View File

@@ -1,36 +0,0 @@
// ==========================================================================
// Base / Fonts
// ==========================================================================
// @include font-face(
// $font-foobar,
// "fonts/Foobar/Regular"
// ) {
// font-style: normal;
// font-weight: 400;
// }
// @include font-face(
// $font-foobar,
// "fonts/Foobar/Medium"
// ) {
// font-style: normal;
// font-weight: 500;
// }
// @include font-face(
// $font-foobar,
// "fonts/Foobar/Semibold"
// ) {
// font-style: normal;
// font-weight: 600;
// }
// @include font-face(
// $font-bazqux,
// "fonts/Bazqux/Regular",
// ("eot", "woff2", "woff", "ttf")
// ) {
// font-style: normal;
// font-weight: 400;
// }

View File

@@ -1,64 +0,0 @@
// ==========================================================================
// Base / Headings
// ==========================================================================
@mixin h {
margin-top: 0;
line-height: $line-height-h;
}
//
// Provide a generic class to apply common heading styles.
//
// @example
// <p class="u-h"></p>
//
//
.o-h {
@include h;
}
//
// Styles for headings 1 through 6 with classes to provide
// a double stranded heading hierarchy, e.g. we semantically
// need an H2, but we want it to be sized like an H1:
//
// @example
// <h2 class="o-h1"></h2>
//
//
h1, .o-h1 {
@extend .o-h;
font-size: rem($font-size-h1);
}
h2, .o-h2 {
@extend .o-h;
font-size: rem($font-size-h2);
}
h3, .o-h3 {
@extend .o-h;
font-size: rem($font-size-h3);
}
h4, .o-h4 {
@extend .o-h;
font-size: rem($font-size-h4);
}
h5, .o-h5 {
@extend .o-h;
font-size: rem($font-size-h5);
}
h6, .o-h6 {
@extend .o-h;
font-size: rem($font-size-h6);
}

View File

@@ -1,63 +0,0 @@
// ==========================================================================
// Base / Page
// ==========================================================================
//
// Simple page-level setup.
//
// 1. Set the default `font-size` and `line-height` for the entire project,
// sourced from our default variables.
// 2. Force scrollbars to always be visible to prevent awkward jumps when
// navigating between pages that do/do not have enough content to produce
// scrollbars naturally.
// 3. Ensure the page always fills at least the entire height of the viewport.
//
html {
overflow-y: scroll; /* [2] */
min-height: 100%; /* [3] */
color: $color;
font-family: $font-family;
line-height: $line-height; /* [1] */
@media (max-width: $to-small) {
font-size: 12px;
}
@media (min-width: $from-small) and (max-width: $to-medium) {
font-size: 13px;
}
@media (min-width: $from-medium) and (max-width: $to-large) {
font-size: 14px;
}
@media (min-width: $from-large) and (max-width: $to-huge) {
font-size: $font-size; /* [1] */
}
@media (min-width: $from-huge) and (max-width: $to-gigantic) {
font-size: 18px;
}
@media (min-width: $from-gigantic) and (max-width: $to-colossal) {
font-size: 21px;
}
@media (min-width: $from-colossal) {
font-size: 24px;
}
}
::selection {
background-color: $selection-background-color;
color: $selection-text-color;
text-shadow: none;
}
a {
@include u-hocus {
color: $link-hover-color;
}
color: $link-color;
}

View File

@@ -1,11 +1,12 @@
// ==========================================================================
// Objects / Buttons
// Components / Buttons
// ==========================================================================
.o-button {
@include u-hocus {
background-color: gray;
}
padding: rem(10px);
.c-button {
padding: rem(15px) rem(20px);
background-color: lightgray;
@include u-hocus {
background-color: darkgray;
}
}

View File

@@ -1,27 +1,40 @@
// ==========================================================================
// Objects / Buttons
// Components / Form
// ==========================================================================
.c-form {
}
.c-form_item {
position: relative;
margin-bottom: rem(30px);
}
// Label
// =============================================================================
.o-label {
// ==========================================================================
.c-form_label {
display: block;
margin-bottom: rem(15px);
margin-bottom: rem(10px);
}
// Input
// =============================================================================
// ==========================================================================
$input-icon-color: 424242; // No #
.o-input {
.c-form_input {
padding: rem(10px);
border-width: 1px;
border-style: solid;
border-color: lightgray;
background-color: white;
border: 1px solid lightgray;
background-color: color(lightest);
&:hover {
border-color: darkgray;
}
&:focus {
border-color: gray;
border-color: dimgray;
}
&::placeholder {
@@ -30,47 +43,27 @@ $input-icon-color: 424242; // No #
}
// Checkbox
// =============================================================================
// ==========================================================================
$checkbox: rem(18px);
$checkbox-icon-color: $input-icon-color;
.o-checkbox {
position: absolute;
width: 0;
opacity: 0;
&:focus {
+ .o-checkbox-label {
&::before {
border-color: gray;
}
}
}
&:checked {
+ .o-checkbox-label {
&::after {
opacity: 1;
}
}
}
}
.o-checkbox-label {
@extend .o-label;
.c-form_checkboxLabel {
@extend .c-form_label;
position: relative;
display: inline-block;
margin-right: 0.5em;
margin-right: rem(10px);
margin-bottom: 0;
padding-left: ($checkbox + rem(10px));
cursor: pointer;
&::before, &::after {
position: absolute;
top: 50%;
left: 0;
display: inline-block;
margin-top: (-$checkbox / 2);
margin-top: math.div(-$checkbox, 2);
padding: 0;
width: $checkbox;
height: $checkbox;
@@ -78,7 +71,8 @@ $checkbox-icon-color: $input-icon-color;
}
&::before {
background-color: $white;
background-color: color(lightest);
border: 1px solid lightgray;
}
&::after {
@@ -86,22 +80,43 @@ $checkbox-icon-color: $input-icon-color;
background-color: transparent;
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2210.5%22%20viewBox%3D%220%200%2013%2010.5%22%20enable-background%3D%22new%200%200%2013%2010.5%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23#{$checkbox-icon-color}%22%20d%3D%22M4.8%205.8L2.4%203.3%200%205.7l4.8%204.8L13%202.4c0%200-2.4-2.4-2.4-2.4L4.8%205.8z%22%2F%3E%3C%2Fsvg%3E");
background-position: center;
background-size: rem(13px);
background-size: rem(12px);
background-repeat: no-repeat;
opacity: 0;
}
&:hover {
&::before {
border-color: darkgray;
}
}
.c-form_checkbox:focus + & {
&::before {
border-color: dimgray;
}
}
.c-form_checkbox:checked + & {
&::after {
opacity: 1;
}
}
}
.c-form_checkbox {
position: absolute;
width: 0;
opacity: 0;
}
// Radio
// =============================================================================
// ==========================================================================
$radio-icon-color: $input-icon-color;
.o-radio {
@extend .o-checkbox;
}
.o-radio-label {
@extend .o-checkbox-label;
.c-form_radioLabel {
@extend .c-form_checkboxLabel;
&::before, &::after {
border-radius: 50%;
@@ -109,25 +124,23 @@ $radio-icon-color: $input-icon-color;
&::after {
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20enable-background%3D%22new%200%200%2013%2013%22%20xml%3Aspace%3D%22preserve%22%3E%3Ccircle%20fill%3D%22%23#{$radio-icon-color}%22%20cx%3D%226.5%22%20cy%3D%226.5%22%20r%3D%226.5%22%2F%3E%3C%2Fsvg%3E");
background-size: rem(8px);
background-size: rem(6px);
}
}
.c-form_radio {
@extend .c-form_checkbox;
}
// Select
// =============================================================================
$select-icon: rem(40px);
$select-icon-color: $input-icon-color;
.o-select {
@extend .o-input;
position: relative;
z-index: 1;
padding-right: $select-icon;
}
.o-select-wrap {
.c-form_select {
position: relative;
cursor: pointer;
&::after {
position: absolute;
@@ -138,17 +151,27 @@ $select-icon-color: $input-icon-color;
width: $select-icon;
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2211.3%22%20viewBox%3D%220%200%2013%2011.3%22%20enable-background%3D%22new%200%200%2013%2011.3%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23#{$select-icon-color}%22%20points%3D%226.5%2011.3%203.3%205.6%200%200%206.5%200%2013%200%209.8%205.6%20%22%2F%3E%3C%2Fsvg%3E");
background-position: center;
background-size: rem(10px);
background-size: rem(8px);
background-repeat: no-repeat;
content: "";
pointer-events: none;
}
}
.c-form_select_input {
@extend .c-form_input;
position: relative;
z-index: 1;
padding-right: $select-icon;
cursor: pointer;
}
// Textarea
// =============================================================================
.o-textarea {
@extend .o-input;
min-height: rem(100px);
.c-form_textarea {
@extend .c-form_input;
min-height: rem(200px);
}

View File

@@ -0,0 +1,79 @@
// ==========================================================================
// Components / Headings
// ==========================================================================
// Font sizes
// ==========================================================================
:root {
// Default
--font-size-h1: #{responsive-value(38px, 90px, $from-xl)};
--font-size-h2: #{responsive-value(34px, 72px, $from-xl)};
--font-size-h3: #{responsive-value(28px, 54px, $from-xl)};
--font-size-h4: #{responsive-value(24px, 40px, $from-xl)};
--font-size-h5: #{responsive-value(20px, 30px, $from-xl)};
--font-size-h6: #{responsive-value(18px, 23px, $from-xl)};
}
// Mixins
// ==========================================================================
@mixin heading {
font-family: ff('sans');
font-weight: $font-weight-medium;
}
@mixin heading-h1 {
font-size: var(--font-size-h1);
line-height: 1.1;
}
@mixin heading-h2 {
font-size: var(--font-size-h2);
line-height: 1.1;
}
@mixin heading-h3 {
font-size: var(--font-size-h3);
line-height: 1.1;
}
@mixin heading-h4 {
font-size: var(--font-size-h4);
line-height: 1.2;
}
@mixin heading-h5 {
font-size: var(--font-size-h5);
line-height: 1.2;
}
@mixin heading-h6 {
font-size: var(--font-size-h6);
line-height: 1.4;
}
// Styles
// ==========================================================================
.c-heading {
@include heading;
&.-h1 {
@include heading-h1;
}
&.-h2 {
@include heading-h2;
}
&.-h3 {
@include heading-h3;
}
&.-h4 {
@include heading-h4;
}
&.-h5 {
@include heading-h5;
}
&.-h6 {
@include heading-h6;
}
}

View File

@@ -0,0 +1,38 @@
// ==========================================================================
// Components / Scrollbar
// ==========================================================================
.c-scrollbar {
position: absolute;
right: 0;
top: 0;
width: 11px;
height: 100vh;
transform-origin: center right;
transition: transform t(normal), opacity t(normal);
opacity: 0;
&:hover {
transform: scaleX(1.45);
}
&:hover, .has-scroll-scrolling &, .has-scroll-dragging & {
opacity: 1;
}
}
.c-scrollbar_thumb {
position: absolute;
top: 0;
right: 0;
background-color: color(darkest);
opacity: 0.5;
width: 7px;
border-radius: 10px;
margin: 2px;
cursor: grab;
.has-scroll-dragging & {
cursor: grabbing;
}
}

View File

@@ -0,0 +1,53 @@
// ==========================================================================
// Components / Texts
// ==========================================================================
// Font sizes
// ==========================================================================
:root {
--font-size-body-regular: #{responsive-value(15px, 17px, $from-lg)};
--font-size-body-medium: #{responsive-value(18px, 23px, $from-lg)};
--font-size-body-small: #{responsive-value(13px, 16px, $from-lg)};
}
// Mixins
// ==========================================================================
@mixin text {
font-family: ff('sans');
}
@mixin body-regular {
font-size: var(--font-size-body-regular);
font-weight: $font-weight-normal;
line-height: 1.2;
}
@mixin body-medium {
font-size: var(--font-size-body-medium);
font-weight: $font-weight-normal;
line-height: 1.2;
}
@mixin body-small {
font-size: var(--font-size-body-small);
font-weight: $font-weight-normal;
line-height: 1.2;
}
// Styles
// ==========================================================================
.c-text {
@include text;
&.-body-regular {
@include body-regular;
}
&.-body-medium {
@include body-medium;
}
&.-body-small {
@include body-small;
}
}

View File

@@ -0,0 +1,185 @@
// ==========================================================================
// Components / Wysiwyg
// ==========================================================================
.c-wysiwyg {
// ==========================================================================
// Margins
// ==========================================================================
& > * + * {
margin-bottom: size-clamp('md');
}
&-first-element,
>:first-child {
margin-top: 0 !important;
padding-top: 0 !important;
}
&-last-element,
>:last-child {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
// ==========================================================================
// Default
// ==========================================================================
// @include text;
// @include body-large;
// ==========================================================================
// Headings
// ==========================================================================
h1,h2,h3,h4,h5,h6 {
// @include heading;
margin-top: 1.5em;
margin-bottom: 1em;
}
h1 {
// @include heading-h3;
}
h2 {
// @include heading-h3;
}
h3 {
// @include heading-h4;
}
h4 {
// @include heading-h5;
}
h5 {
// @include heading-h6;
}
h6 {
// @include heading-h6;
}
// ==========================================================================
// Lists
// ==========================================================================
ul,
ol {
list-style: none;
padding-left: 0;
> li {
position: relative;
padding-left: 1.5em;
}
}
ul {
> li {
&::before {
content: "";
position: absolute;
left: 0;
top: calc(50% - 3px);
width: 6px;
height: 6px;
background-color: currentColor;
border-radius: 50%;
}
}
}
ol {
counter-reset: counter;
> li {
counter-increment: counter;
&::before {
content: counter(counter);
position: absolute;
left: 0;
}
}
}
// ==========================================================================
// Link
// ==========================================================================
a {
color: $color-link;
&:focus-visible {
color: $color-link-focus;
}
@media (hover: hover) {
&:hover {
color: $color-link-hover;
}
}
}
// ==========================================================================
// Image
// ==========================================================================
img {
width: 100%;
}
// ==========================================================================
// iFrame
// ==========================================================================
iframe {
display: block;
margin-left: auto;
margin-right: auto;
&:not([width]) {
width: 100%;
}
&:not([height]) {
height: auto;
}
}
// ==========================================================================
// Table
// ==========================================================================
table {
width: 100%;
}
caption {
// @include text;
// @include body-small;
margin: 1em 0;
}
// ==========================================================================
// Blockquote
// ==========================================================================
blockquote {
// @include heading;
// @include heading-h3;
quotes: "" "" "" "";
padding: 0;
p {
&::before {
content: open-quote;
}
&::after {
content: close-quote;
}
}
& + p {
padding-top: 0;
}
}
}

View File

@@ -0,0 +1,5 @@
// ==========================================================================
// Critical CSS
// ==========================================================================
$assets-path: "assets/";

View File

@@ -0,0 +1,55 @@
// ==========================================================================
// Elements / Document
// ==========================================================================
//
// Simple page-level setup.
//
// 1. Includes fonts
// 2. Ensure the page always fills at least the entire height of the viewport.
// 3. Set the default `font-size` and `line-height` for the entire project,
// sourced from our default variables.
@include font-faces($font-faces, $font-dir); // [1]
html {
min-height: 100%; // [2]
line-height: $line-height; // [3]
font-family: ff("sans");
color: $font-color;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@media (max-width: $to-sm) {
font-size: $font-size - 2px;
}
@media (min-width: $from-sm) and (max-width: $to-lg) {
font-size: $font-size - 1px;
}
@media (min-width: $from-lg) and (max-width: $to-2xl) {
font-size: $font-size;
}
@media (min-width: $from-2xl) and (max-width: $to-3xl) {
font-size: $font-size + 1px;
}
@media (min-width: $from-3xl) {
font-size: $font-size + 2px;
}
&.is-loading {
cursor: wait;
}
}
body {
}
::selection {
background-color: $color-selection-background;
color: $color-selection-text;
text-shadow: none;
}

View File

@@ -0,0 +1,124 @@
// ==========================================================================
// Elements / Normalize
// ==========================================================================
// Modern CSS Normalize
// Based on the reset by Andy.set with some tweaks.
// Original by Andy.set: https://piccalil.li/blog/a-more-modern-css-reset/
// Review by Chris collier: https://chriscoyier.net/2023/10/03/being-picky-about-a-css-reset-for-fun-pleasure/
// Box sizing rules
*,
*:after,
*:before {
box-sizing: border-box;
}
// Prevent font size inflation
html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
}
// Remove default margin in favour of better control in authored CSS
p,
h1,
h2,
h3,
h4,
h5,
h6,
dl,
dd,
figure,
blockquote {
margin-block: unset;
}
// Remove list styles on ul, ol elements with a class, which suggests default styling will be removed
ul[class],
ol[class] {
margin: 0;
padding: 0;
list-style: none;
}
// Set core defaults
html {
line-height: 1.5;
}
body {
margin: unset;
}
// Set shorter line heights on headings and interactive elements
h1,
h2,
h3,
h4,
h5,
h6,
input,
label,
button {
line-height: 1.1;
}
// Balance text wrapping on headings
h1,
h2,
h3,
h4,
h5,
h6 {
text-wrap: balance;
}
// Remove a elements default styles if they have a class
a[class] {
color: inherit;
text-decoration: none;
}
// Make assets easier to work with
img,
svg,
canvas,
picture {
display: block;
max-inline-size: 100%;
block-size: auto;
}
// Inherit fonts for inputs and buttons
input,
button,
select,
textarea {
font: inherit;
}
// Make sure textareas without a rows attribute are not tiny
textarea:not([rows]) {
min-height: 10em;
}
// Anything that has been anchored to should have extra scroll margin
:target {
scroll-margin-block: 1rlh;
}
// Reduced mootion preference
@media (prefers-reduced-motion: reduce) {
*,
*:after,
*:before {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}

View File

@@ -1,35 +0,0 @@
// ==========================================================================
// Generic / Buttons
// ==========================================================================
//
// 1. Allow us to style box model properties.
// 2. Fixes odd inner spacing in IE7.
// 3. Reset/normalize some styles.
// 4. Line different sized buttons up a little nicer.
// 5. Make buttons inherit font styles (often necessary when styling `input`s as buttons).
// 6. Force all button-styled elements to appear clickable.
//
button,
.o-button {
@include u-hocus {
text-decoration: none;
}
display: inline-block; /* [1] */
overflow: visible; /* [2] */
margin: 0; /* [3] */
padding: 0;
outline: 0;
border: 0;
background: none transparent;
color: inherit;
vertical-align: middle; /* [4] */
text-align: center; /* [3] */
text-decoration: none;
text-transform: none;
font: inherit; /* [5] */
line-height: normal;
cursor: pointer; /* [6] */
user-select: none;
}

View File

@@ -1,44 +0,0 @@
// ==========================================================================
// Generic / Forms
// ==========================================================================
input,
select,
textarea {
display: block;
margin: 0;
padding: 0;
width: 100%;
outline: 0;
border: 0;
border-radius: 0;
background: none transparent;
color: inherit;
font: inherit;
line-height: normal;
appearance: none;
}
select {
text-transform: none;
&::-ms-expand {
display: none;
}
&::-ms-value {
background: none;
color: inherit;
}
// Remove Firefox :focus dotted outline, breaks color inherit
// &:-moz-focusring {
// color: transparent;
// text-shadow: 0 0 0 #000000; // Text :focus color
// }
}
textarea {
overflow: auto;
resize: vertical;
}

View File

@@ -1,72 +0,0 @@
// ==========================================================================
// Generic
// ==========================================================================
html {
box-sizing: border-box;
}
//
// Add the correct display in IE 10-.
// 1. Add the correct display in IE.
//
template, /* [1] */
[hidden] {
display: none;
}
*,
:before,
:after {
box-sizing: inherit;
}
address {
font-style: inherit;
}
dfn,
cite,
em,
i {
font-style: italic;
}
b,
strong {
font-weight: $bold;
}
a {
text-decoration: none;
svg {
pointer-events: none;
}
}
/**
* 1. Single taps should be dispatched immediately on clickable elements
*/
a, area, button, input, label, select, textarea, [tabindex] {
-ms-touch-action: manipulation; /* [1] */
touch-action: manipulation;
}
[hreflang] > abbr[title] {
text-decoration: none;
}
table {
border-spacing: 0;
border-collapse: collapse;
}
hr {
display: block;
margin: 1em 0;
padding: 0;
height: 1px;
border: 0;
border-top: 1px solid #CCCCCC;
}

View File

@@ -1,58 +0,0 @@
// ==========================================================================
// Generic / Media
// ==========================================================================
//
// 1. Setting `vertical-align` removes the whitespace that appears under `img`
// elements when they are dropped into a page as-is. Safer alternative to
// using `display: block;`.
//
audio,
canvas,
iframe,
img,
svg,
video {
vertical-align: middle; /* [1] */
}
//
// Add the correct display in iOS 4-7.
//
audio:not([controls]) {
display: none;
height: 0;
}
//
// 2. Fluid media for responsive purposes.
//
img,
svg {
max-width: 100%; /* [2] */
height: auto;
//
// 4. If a `width` and/or `height` attribute have been explicitly defined, lets
// not make the image fluid.
//
&[width], /* [4] */
&[height] {
/* [4] */
max-width: none;
}
}
//
// 4. Offset `alt` text from surrounding copy.
//
img {
font-style: italic; /* [4] */
}
//
// 5. SVG elements should fallback to their surrounding text color.
//
svg {
fill: currentColor; /* [5] */
}

View File

@@ -2,66 +2,71 @@
// Main
// ==========================================================================
// Settings
// Modules
// ==========================================================================
@import "settings/config.colors";
@import "settings/config";
// ==========================================================================
@use "sass:math";
// Tools
// ==========================================================================
@import "tools/maths";
@import "tools/functions";
@import "tools/mixins";
@import "tools/fonts";
@import "tools/layout";
// @import "tools/ratio";
// @import "tools/layout";
// @import "tools/widths";
// @import "tools/familly";
// @import "tools/family";
// Generic
// Settings
// ==========================================================================
@import "node_modules/normalize.css/normalize";
@import "generic/generic";
@import "generic/media";
@import "generic/form";
@import "generic/button";
// Base
// ==========================================================================
@import "base/fonts";
@import "base/page";
@import "base/headings";
// Objects
// ==========================================================================
@import "objects/container";
// @import "objects/crop";
// @import "objects/ratio";
// @import "objects/table";
@import "objects/layout";
@import "objects/form";
@import "objects/button";
@import "objects/pjax";
@import "objects/scroll";
@import "settings/config";
@import "settings/config.breakpoints";
@import "settings/config.colors";
@import "settings/config.eases";
@import "settings/config.fonts";
@import "settings/config.spacings";
@import "settings/config.speeds";
@import "settings/config.zindexes";
@import "settings/config.variables";
// Vendors
// ==========================================================================
// @import "vendors/vendor";
@import "node_modules/locomotive-scroll/dist/locomotive-scroll";
// Elements
// ==========================================================================
@import "elements/normalize";
@import "elements/document";
// Objects
// ==========================================================================
@import "objects/container";
@import "objects/ratio";
@import "objects/icons";
@import "objects/grid";
// @import "objects/layout";
// @import "objects/table";
// Components
// ==========================================================================
// @import "components/component";
// Templates
// ==========================================================================
// @import "templates/template";
@import "components/heading";
@import "components/text";
@import "components/button";
@import "components/form";
@import "components/wysiwyg";
// Utilities
// ==========================================================================
@import "utilities/ratio";
@import "utilities/grid-column";
// @import "utilities/widths";
// @import "utilities/align";
// @import "utilities/helpers";
// @import "utilities/states";
// @import "utilities/headings";
// @import "utilities/spacing";
// @import "utilities/widths";
@import "utilities/spacing";
// @import "utilities/print";

View File

@@ -2,7 +2,6 @@
// Objects / Container
// ==========================================================================
//
// Page-level constraining and wrapping elements.
//
// > In programming languages the word *container* is generally used for structures
@@ -10,18 +9,10 @@
// > A *wrapper* instead is something that wraps around a single object to provide
// more functionalities and interfaces to it.
// @link http://stackoverflow.com/a/13202141/140357
//
/* stylelint-disable */
@if (type-of($container-width) != number) {
@error "`#{$container-width}` needs to be a number."
}
/* stylelint-enable */
.o-container {
margin-right: auto;
margin-left: auto;
padding-right: $padding;
padding-left: $padding;
max-width: $container-width;
padding-left: var(--grid-margin);
padding-right: var(--grid-margin);
}

View File

@@ -1,88 +0,0 @@
// ==========================================================================
// Objects / Crop
// ==========================================================================
//
// @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.crop.scss
//
// A list of cropping ratios that get generated as modifier classes.
$crop-ratios: (
(2:1),
(4:3),
(16:9),
) !default;
/**
* Provide a cropping container in order to display media (usually images)
* cropped to certain ratios.
*
* 1. Set up a positioning context in which the image can sit.
* 2. This is the crucial part: where the cropping happens.
*/
.o-crop {
position: relative; /* [1] */
display: block;
overflow: hidden; /* [2] */
}
/**
* Apply this class to the content (usually `img`) that needs cropping.
*
* 1. Images default positioning is top-left in the cropping box.
* 2. Make sure the media doesnt stop itself too soon.
*/
.o-crop_content {
position: absolute;
top: 0; /* [1] */
left: 0; /* [1] */
max-width: none; /* [2] */
/**
* We can position the media in different locations within the cropping area.
*/
&.-right {
right: 0;
left: auto;
}
&.-bottom {
top: auto;
bottom: 0;
}
&.-center {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
/* stylelint-disable */
//
// Generate a series of crop classes to be used like so:
//
// @example
// <div class="o-crop -16:9">
//
//
.o-crop {
@each $crop in $crop-ratios {
@each $antecedent, $consequent in $crop {
@if (type-of($antecedent) != number) {
@error "`#{$antecedent}` needs to be a number."
}
@if (type-of($consequent) != number) {
@error "`#{$consequent}` needs to be a number."
}
&.-#{$antecedent}\:#{$consequent} {
padding-bottom: ($consequent/$antecedent) * 100%;
}
}
}
}
/* stylelint-enable */

View File

@@ -0,0 +1,178 @@
// ==========================================================================
// Grid helper
// ==========================================================================
// Help: https://css-tricks.com/snippets/css/complete-guide-grid/
//
/**
* Usage:
*
* ```html
* <div class="o-grid -col-4 -col-12@from-medium -gutters">
* <div class="o-grid_item u-gc-1/2 u-gc-3/9@from-medium">
* <p>Hello</p>
* </div>
* <div class="o-grid_item u-gc-3/4 u-gc-9/13@from-medium">
* <p>Hello</p>
* </div>
* </div>
* ```
*/
.o-grid {
display: grid;
width: 100%;
&:is(ul, ol) {
margin: 0;
padding: 0;
list-style: none;
}
// ==========================================================================
// Cols
// ==========================================================================
// Responsive grid columns based on `--grid-columns`
&.-cols {
grid-template-columns: repeat(var(--grid-columns), 1fr);
}
&.-col-#{$base-column-nb} {
grid-template-columns: repeat(#{$base-column-nb}, 1fr);
}
&.-col-4 {
grid-template-columns: repeat(4, 1fr);
}
&.-col-#{$base-column-nb}\@from-md {
@media (min-width: $from-md) {
grid-template-columns: repeat(#{$base-column-nb}, 1fr);
}
}
// ==========================================================================
// Gutters
// ==========================================================================
// Gutters rows and columns
&.-gutters {
gap: var(--grid-gutter);
column-gap: var(--grid-gutter);
}
// ==========================================================================
// Modifiers
// ==========================================================================
&.-full-height {
height: 100%;
}
// ==========================================================================
// Aligns
// ==========================================================================
// ==========================================================================
// Items inside cells
//
&.-top-items {
align-items: start;
}
&.-right-items {
justify-items: end;
}
&.-bottom-items {
align-items: end;
}
&.-left-items {
justify-items: start;
}
&.-center-items {
align-items: center;
justify-items: center;
}
&.-center-items-x {
justify-items: center;
}
&.-center-items-y {
align-items: center;
}
&.-stretch-items {
align-items: stretch;
justify-items: stretch;
}
// ==========================================================================
// Cells
//
&.-top-cells {
align-content: start;
}
&.-right-cells {
justify-content: end;
}
&.-bottom-cells {
align-content: end;
}
&.-left-cells {
justify-content: start;
}
&.-center-cells {
align-content: center;
justify-content: center;
}
&.-center-cells-x {
justify-content: center;
}
&.-center-cells-y {
align-content: center;
}
&.-stretch-cells {
align-content: stretch;
justify-content: stretch;
}
&.-space-around-cells {
align-content: space-around;
justify-content: space-around;
}
&.-space-around-cells-x {
justify-content: space-around;
}
&.-space-around-cells-y {
align-content: space-around;
}
&.-space-between-cells {
justify-content: space-between;
align-content: space-between;
}
&.-space-between-cells-x {
justify-content: space-between;
}
&.-space-between-cells-y {
align-content: space-between;
}
&.-space-evenly-cells {
justify-content: space-evenly;
align-content: space-evenly;
}
&.-space-evenly-cells-x {
justify-content: space-evenly;
}
&.-space-evenly-cells-y {
align-content: space-evenly;
}
}
// ==========================================================================
// Grid item
// ==========================================================================
// By default, a grid item takes full width of its parent.
//
.o-grid_item {
grid-column-start: var(--gc-start, 1);
grid-column-end: var(--gc-end, -1);
&.-align-end {
align-self: end;
}
}

View File

@@ -0,0 +1,58 @@
// ==========================================================================
// Objects / SVG Icons
// ==========================================================================
// Markup
//
// 1. If icon is accessible and has a title
// 2. If icon is decorative
//
// <i class="o-icon ${modifier}">
// <svg
// class="svg-${icon-name}"
// xmlns="http://www.w3.org/2000/svg"
// role="img" [1]
// aria-hidden="true" [2]
// focusable="false" [2]
// aria-labelledby="${id}" [1]
// >
// <title id="${id}"> [1]
// Locomotive
// </title>
// <use xlink:href="assets/images/sprite.svg#${icon-name}" xmlns:xlink="http://www.w3.org/1999/xlink"/>
// </svg>
// </i>
// Global styles for icones
// ==========================================================================
.o-icon {
display: inline-block;
vertical-align: middle;
svg {
--icon-height: calc(var(--icon-width) * math.div(1, (var(--icon-ratio))));
display: block;
width: var(--icon-width);
height: var(--icon-height);
fill: currentColor;
}
}
// SVG sizes
// ==========================================================================
// // Logo
// .svg-logo {
// --icon-width: #{rem(100px)};
// --icon-ratio: math.div(20, 30); // width/height based on svg viewBox
// // Sizes
// .o-icon.-big & {
// --icon-width: #{rem(200px)};
// }
// }

View File

@@ -2,41 +2,41 @@
// Objects / Layout
// ==========================================================================
//
// Grid-like layout system.
//
// The layout object provides us with a column-style layout system. This file
// contains the basic structural elements, but classes should be complemented
// with width utilities, for example:
//
// @example
// <div class="o-layout">
// <div class="o-layout_item u-1/1 u-1/3@medium">
// </div>
// <div class="o-layout_item u-1/2 u-1/3@medium">
// </div>
// <div class="o-layout_item u-1/2 u-1/3@medium">
// </div>
// </div>
//
// We can also manipulate entire layout systems by adding a series of modifiers
// to the `.o-layout` block. For example:
//
// @example
// <div class="o-layout -reverse">
//
// This will reverse the displayed order of the system so that it runs in the
// opposite order to our source, effectively flipping the system over.
//
// @example
// <div class="o-layout -[right|center]">
//
// This will cause the system to fill up from either the centre or the right
// hand side. Default behaviour is to fill up the layout system from the left.
//
// @requires tools/layout
// @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss
//
////
/// Grid-like layout system.
///
/// The layout object provides us with a column-style layout system. This file
/// contains the basic structural elements, but classes should be complemented
/// with width utilities, for example:
///
/// @example
/// <div class="o-layout">
/// <div class="o-layout_item u-1/1 u-1/3@medium">
/// </div>
/// <div class="o-layout_item u-1/2 u-1/3@medium">
/// </div>
/// <div class="o-layout_item u-1/2 u-1/3@medium">
/// </div>
/// </div>
///
/// We can also manipulate entire layout systems by adding a series of modifiers
/// to the `.o-layout` block. For example:
///
/// @example
/// <div class="o-layout -reverse">
///
/// This will reverse the displayed order of the system so that it runs in the
/// opposite order to our source, effectively flipping the system over.
///
/// @example
/// <div class="o-layout -[right|center]">
///
/// This will cause the system to fill up from either the centre or the right
/// hand side. Default behaviour is to fill up the layout system from the left.
///
/// @requires tools/layout
/// @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss
////
.o-layout {
@include o-layout;
@@ -47,7 +47,7 @@
}
&.-gutter-small {
margin-left: rem(-$unit/2);
margin-left: rem(-$unit-small);
}
// Horizontal aligment modifiers
@@ -94,7 +94,7 @@
}
.o-layout.-gutter-small > & {
padding-left: rem($unit/2);
padding-left: rem($unit-small);
}
// Vertical alignment modifiers

View File

@@ -1,11 +0,0 @@
.o-pjax_wrapper {
height: 100%;
overflow: hidden;
}
.o-pjax_container {
height: 100%;
overflow: hidden;
}

View File

@@ -2,28 +2,13 @@
// Objects / Ratio
// ==========================================================================
// Create ratio-bound content blocks, to keep media (e.g. images, videos) in
// their correct aspect ratios.
//
// @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.ratio.scss
// http://alistapart.com/article/creating-intrinsic-ratios-for-video
//
// 1. Default cropping is a 1:1 ratio (i.e. a perfect square).
// A list of aspect ratios that get generated as modifier classes.
$aspect-ratios: (
(2:1),
(4:3),
(16:9),
) !default;
/**
* Create ratio-bound content blocks, to keep media (e.g. images, videos) in
* their correct aspect ratios.
*
* http://alistapart.com/article/creating-intrinsic-ratios-for-video
*
* 1. Default cropping is a 1:1 ratio (i.e. a perfect square).
*/
.o-ratio {
position: relative;
display: block;
@@ -31,13 +16,14 @@ $aspect-ratios: (
&:before {
display: block;
padding-bottom: 100%; /* [1] */
padding-bottom: 100%; // [1]
width: 100%;
content: "";
}
}
.o-ratio_content,
.o-ratio > img,
.o-ratio > iframe,
.o-ratio > embed,
.o-ratio > object {
@@ -46,34 +32,5 @@ $aspect-ratios: (
bottom: 0;
left: 0;
width: 100%;
height: 100%;
// height: 100%;
}
/* stylelint-disable */
//
// Generate a series of ratio classes to be used like so:
//
// @example
// <div class="o-ratio -16:9">
//
//
.o-ratio {
@each $ratio in $aspect-ratios {
@each $antecedent, $consequent in $ratio {
@if (type-of($antecedent) != number) {
@error "`#{$antecedent}` needs to be a number."
}
@if (type-of($consequent) != number) {
@error "`#{$consequent}` needs to be a number."
}
&.-#{$antecedent}\:#{$consequent}::before {
padding-bottom: ($consequent/$antecedent) * 100%;
}
}
}
}
/* stylelint-enable */

View File

@@ -1,63 +0,0 @@
html.has-smooth-scroll {
overflow: hidden;
}
.o-scroll{
html.has-smooth-scroll & {
height: 100vh;
position: relative;
overflow: hidden;
}
}
.scroll-content {
transform: translate3d(0,0,0);
margin: 0;
overflow: visible;
height: 100%;
}
// Scrollbar
// ==========================================================================
[data-scrollbar],[scrollbar],scrollbar{display:block;position:relative}[data-scrollbar] .scroll-content,[scrollbar] .scroll-content,scrollbar .scroll-content{-webkit-transform:translateZ(0);transform:translateZ(0);will-change:transform}[data-scrollbar].sticky .scrollbar-track,[scrollbar].sticky .scrollbar-track,scrollbar.sticky .scrollbar-track{background:hsla(0,0%,87%,.75)}[data-scrollbar] .scrollbar-track,[scrollbar] .scrollbar-track,scrollbar .scrollbar-track{position:absolute;opacity:0;z-index:1;-webkit-transition:opacity .5s ease-out,background .5s ease-out;transition:opacity .5s ease-out,background .5s ease-out;background:none}[data-scrollbar] .scrollbar-track.show,[data-scrollbar] .scrollbar-track:hover,[scrollbar] .scrollbar-track.show,[scrollbar] .scrollbar-track:hover,scrollbar .scrollbar-track.show,scrollbar .scrollbar-track:hover{opacity:1}[data-scrollbar] .scrollbar-track:hover,[scrollbar] .scrollbar-track:hover,scrollbar .scrollbar-track:hover{background:hsla(0,0%,87%,.75)}[data-scrollbar] .scrollbar-track-x,[scrollbar] .scrollbar-track-x,scrollbar .scrollbar-track-x{bottom:0;left:0;width:100%;height:8px}[data-scrollbar] .scrollbar-track-y,[scrollbar] .scrollbar-track-y,scrollbar .scrollbar-track-y{top:0;right:0;width:8px;height:100%}[data-scrollbar] .scrollbar-thumb,[scrollbar] .scrollbar-thumb,scrollbar .scrollbar-thumb{position:absolute;top:0;left:0;width:8px;height:8px;background:rgba(0,0,0,.5);border-radius:4px}[data-scrollbar] .overscroll-glow,[scrollbar] .overscroll-glow,scrollbar .overscroll-glow{position:absolute;top:0;left:0;width:100%;height:100%}
.scrollbar-track {
user-select: none;
background-color: transparent !important;
width: 14px !important;
opacity: 0 !important;
z-index: 99999 !important;
.scrolling & {
opacity: 0.75 !important;
}
&:hover {
opacity: 1 !important;
background-color: #fafafa !important;
}
}
.scrollbar-thumb {
position: relative;
width: 14px !important;
background-color: transparent !important;
&::after {
content: "";
position: absolute;
top: 3px;
right: 3px;
bottom: 3px;
left: 3px;
background-color: #c1c1c1;
border-radius: 4px;
transition: background-color $speed $easing;
}
&:hover {
&::after {
background-color: #7d7d7d;
}
}
}

View File

@@ -1,14 +1,14 @@
// ==========================================================================
// Objects / Tables
// ==========================================================================
.o-table {
width: 100%;
/**
* Force all cells within a table to occupy the same width as each other.
*
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout#Values
*/
// Force all cells within a table to occupy the same width as each other.
//
// @link https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout#Values
&.-fixed {
table-layout: fixed;
}

View File

@@ -0,0 +1,92 @@
// ==========================================================================
// Settings / Config / Breakpoints
// ==========================================================================
// Breakpoints
// ==========================================================================
$breakpoints: (
"2xs": 340px,
"xs": 500px,
"sm": 700px,
"md": 1000px,
"lg": 1200px,
"xl": 1400px,
"2xl": 1600px,
"3xl": 1800px,
"4xl": 2000px,
"5xl": 2400px
);
// Functions
// ==========================================================================
// Creates a min-width or max-width media query expression.
//
// @param {string} $breakpoint The breakpoint.
// @param {string} $type Either "min" or "max".
// @return {string}
@function mq($breakpoint, $type: "min") {
@if not map-has-key($breakpoints, $breakpoint) {
@warn "Unknown media query breakpoint: `#{$breakpoint}`";
}
$value: map-get($breakpoints, $breakpoint);
@if ($type == "min") {
@return "(min-width: #{$value})";
}
@if ($type == "max") {
@return "(max-width: #{$value - 1px})";
}
@error "Unknown media query type: #{$type}";
}
// Creates a min-width media query expression.
//
// @param {string} $breakpoint The breakpoint.
// @return {string}
@function mq-min($breakpoint) {
@return mq($breakpoint, "min");
}
// Creates a max-width media query expression.
//
// @param {string} $breakpoint The breakpoint.
// @return {string}
@function mq-max($breakpoint) {
@return mq($breakpoint, "max");
}
// Creates a min-width and max-width media query expression.
//
// @param {string} $from The min-width breakpoint.
// @param {string} $until The max-width breakpoint.
// @return {string}
@function mq-between($breakpointMin, $breakpointMax) {
@return "#{mq-min($breakpointMin)} and #{mq-max($breakpointMax)}";
}
// Legacy
// ==========================================================================
$from-xs: map-get($breakpoints, "xs") !default;
$to-xs: map-get($breakpoints, "xs") - 1 !default;
$from-sm: map-get($breakpoints, "sm") !default;
$to-sm: map-get($breakpoints, "sm") - 1 !default;
$from-md: map-get($breakpoints, "md") !default;
$to-md: map-get($breakpoints, "md") - 1 !default;
$from-lg: map-get($breakpoints, "lg") !default;
$to-lg: map-get($breakpoints, "lg") - 1 !default;
$from-xl: map-get($breakpoints, "xl") !default;
$to-xl: map-get($breakpoints, "xl") - 1 !default;
$from-2xl: map-get($breakpoints, "2xl") !default;
$to-2xl: map-get($breakpoints, "2xl") - 1 !default;
$from-3xl: map-get($breakpoints, "3xl") !default;
$to-3xl: map-get($breakpoints, "3xl") - 1 !default;

View File

@@ -3,23 +3,57 @@
// ==========================================================================
// Palette
// =============================================================================
$white: #FFFFFF;
$black: #000000;
// ==========================================================================
$colors: (
primary: #3297FD,
lightest: #FFFFFF,
darkest: #000000,
);
// Function
// ==========================================================================
// Returns color code.
//
// ```scss
// .c-box {
// color: color(primary);
// }
// ```
//
// @param {string} $key - The color key in $colors.
// @param {number} $alpha - The alpha for the color value.
// @return {color}
@function color($key, $alpha: 1) {
@if not map-has-key($colors, $key) {
@error "Unknown '#{$key}' in $colors.";
}
@if($alpha < 0 or $alpha > 1) {
@error "Alpha '#{$alpha}' must be in range [0, 1].";
}
$color: map-get($colors, $key);
@return rgba($color, $alpha);
}
// Specifics
// ==========================================================================
// Specific
// =============================================================================
// Link
$link-color: #1A0DAB;
$link-focus-color: #1A0DAB;
$link-hover-color: darken(#1A0DAB, 10%);
// Selection
$selection-text-color: #3297FD;
$selection-background-color: #FFFFFF;
$color-link: color(primary);
$color-link-focus: color(primary);
$color-link-hover: darken(color(primary), 10%);
// Social Colors
// =============================================================================
$facebook-color: #3B5998;
$instagram-color: #E1306C;
$youtube-color: #CD201F;
$twitter-color: #1DA1F2;
// Selection
$color-selection-text: color(lightest);
$color-selection-background: color(darkest);
// Socials
$color-facebook: #3B5998;
$color-instagram: #E1306C;
$color-youtube: #CD201F;
$color-twitter: #1DA1F2;

View File

@@ -0,0 +1,78 @@
// ==========================================================================
// Settings / Config / Eases
// ==========================================================================
// Eases
// ==========================================================================
$eases: (
// Power 1
"power1.in": cubic-bezier(0.550, 0.085, 0.680, 0.530),
"power1.out": cubic-bezier(0.250, 0.460, 0.450, 0.940),
"power1.inOut": cubic-bezier(0.455, 0.030, 0.515, 0.955),
// Power 2
"power2.in": cubic-bezier(0.550, 0.055, 0.675, 0.190),
"power2.out": cubic-bezier(0.215, 0.610, 0.355, 1.000),
"power2.inOut": cubic-bezier(0.645, 0.045, 0.355, 1.000),
// Power 3
"power3.in": cubic-bezier(0.895, 0.030, 0.685, 0.220),
"power3.out": cubic-bezier(0.165, 0.840, 0.440, 1.000),
"power3.inOut": cubic-bezier(0.770, 0.000, 0.175, 1.000),
// Power 4
"power4.in": cubic-bezier(0.755, 0.050, 0.855, 0.060),
"power4.out": cubic-bezier(0.230, 1.000, 0.320, 1.000),
"power4.inOut": cubic-bezier(0.860, 0.000, 0.070, 1.000),
// Expo
"expo.in": cubic-bezier(0.950, 0.050, 0.795, 0.035),
"expo.out": cubic-bezier(0.190, 1.000, 0.220, 1.000),
"expo.inOut": cubic-bezier(1.000, 0.000, 0.000, 1.000),
// Back
"back.in": cubic-bezier(0.600, -0.280, 0.735, 0.045),
"back.out": cubic-bezier(0.175, 00.885, 0.320, 1.275),
"back.inOut": cubic-bezier(0.680, -0.550, 0.265, 1.550),
// Sine
"sine.in": cubic-bezier(0.470, 0.000, 0.745, 0.715),
"sine.out": cubic-bezier(0.390, 0.575, 0.565, 1.000),
"sine.inOut": cubic-bezier(0.445, 0.050, 0.550, 0.950),
// Circ
"circ.in": cubic-bezier(0.600, 0.040, 0.980, 0.335),
"circ.out": cubic-bezier(0.075, 0.820, 0.165, 1.000),
"circ.inOut": cubic-bezier(0.785, 0.135, 0.150, 0.860),
// Misc
"bounce": cubic-bezier(0.17, 0.67, 0.3, 1.33),
"slow.out": cubic-bezier(.04,1.15,0.4,.99),
"smooth": cubic-bezier(0.380, 0.005, 0.215, 1),
);
// Default value for ease()
$ease-default: "power2.out" !default;
// Function
// ==========================================================================
// Returns ease curve.
//
// ```scss
// .c-box {
// transition-timing-function: ease("power2.out");
// }
// ```
//
// @param {string} $key - The ease key in $eases.
// @return {easing-function}
@function ease($key: $ease-default) {
@if not map-has-key($eases, $key) {
@error "Unknown '#{$key}' in $eases.";
}
@return map-get($eases, $key);
}

View File

@@ -0,0 +1,98 @@
// ==========================================================================
// Settings / Config / Breakpoints
// ==========================================================================
// Font fallbacks (retrieved from systemfontstack.com on 2022-05-31)
// ==========================================================================
$font-fallback-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
$font-fallback-serif: Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
$font-fallback-mono: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
// Typefaces
// ==========================================================================
// List of custom font faces as tuples.
//
// ```
// <font-name> <font-file-basename> <font-weight> <font-style>
// ```
$font-faces: (
("Source Sans", "SourceSans3-Bold", 700, normal),
("Source Sans", "SourceSans3-BoldIt", 700, italic),
("Source Sans", "SourceSans3-Regular", 400, normal),
("Source Sans", "SourceSans3-RegularIt", 400, italic),
);
// Map of font families.
//
// ```
// <font-id>: (<font-name>, <font-fallbacks>)
// ```
$font-families: (
sans: join("Source Sans", $font-fallback-sans, $separator: comma),
);
// Font directory
$font-dir: "../fonts/";
// Functions
// ==========================================================================
// Imports the custom font.
//
// The mixin expects font files to be woff and woff2.
//
// @param {List} $webfont - A custom font to import, as a tuple:
// `<font-name> <font-file-basename> <font-weight> <font-style>`.
// @param {String} $dir - The webfont directory path.
// @output The `@font-face` at-rule specifying the custom font.
@mixin font-face($webfont, $dir) {
@font-face {
font-display: swap;
font-family: nth($webfont, 1);
src: url("#{$dir}#{nth($webfont, 2)}.woff2") format("woff2"),
url("#{$dir}#{nth($webfont, 2)}.woff") format("woff");
font-weight: #{nth($webfont, 3)};
font-style: #{nth($webfont, 4)};
}
}
// Imports the list of custom fonts.
//
// @require {mixin} font-face
//
// @param {List<List>} $webfonts - List of custom fonts to import.
// See `font-face` mixin for details.
// @param {String} $dir - The webfont directory path.
// @output The `@font-face` at-rules specifying the custom fonts.
@mixin font-faces($webfonts, $dir) {
@if (length($webfonts) > 0) {
@if (type-of(nth($webfonts, 1)) == "list") {
@each $webfont in $webfonts {
@include font-face($webfont, $dir);
}
} @else {
@include font-face($webfonts, $dir);
}
}
}
// Retrieves the font family stack for the given font ID.
//
// @require {variable} $font-families - See settings directory.
//
// @param {String} $font-family - The custom font ID.
// @throws Error if the $font-family does not exist.
// @return {List} The font stack.
@function ff($font-family) {
@if not map-has-key($font-families, $font-family) {
@error "No font-family found in $font-families map for `#{$font-family}`.";
}
$value: map-get($font-families, $font-family);
@return $value;
}

View File

@@ -4,69 +4,42 @@
// Context
// =============================================================================
// The current stylesheet context. Available values: frontend, editor.
$context: frontend !default;
// Path is relative to the stylesheets directory.
$assets-path: "../" !default;
// Typefaces
// =============================================================================
$font-sans-serif: sans-serif;
// Typography
// =============================================================================
// Base
$font-size: 16px;
$line-height: 24px / $font-size;
$font-family: $font-sans-serif;
$color: #222222;
// Headings
$font-size-h1: 36px !default;
$font-size-h2: 28px !default;
$font-size-h3: 24px !default;
$font-size-h4: 20px !default;
$font-size-h5: 18px !default;
$font-size-h6: 16px !default;
$line-height-h: $line-height;
// Weights
$light: 300;
$normal: 400;
$medium: 500;
$bold: 700;
// Transitions
// Base
$font-size: 16px;
$line-height: math.div(24px, $font-size);
$font-color: color(darkest);
// Weights
$font-weight-light: 300;
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-bold: 700;
// Transition defaults
// =============================================================================
$speed: 0.3s;
$easing: linear;
$speed: t(normal);
$easing: ease("power2.out");
// Spacing Units
// =============================================================================
$unit: 60px;
$unit-small: 30px;
$unit: 60px;
$unit-small: 20px;
$vw-viewport: 1440;
// Container
// ==========================================================================
$container-width: 2000px;
$padding: $unit;
$padding: $unit;
// Breakpoints
// =============================================================================
$from-tiny: 500px !default;
$to-tiny: $from-tiny - 1 !default;
$from-small: 700px !default;
$to-small: $from-small - 1 !default;
$from-medium: 1000px !default;
$to-medium: $from-medium - 1 !default;
$from-large: 1200px !default;
$to-large: $from-large - 1 !default;
$from-big: 1400px !default;
$to-big: $from-big - 1 !default;
$from-huge: 1600px !default;
$to-huge: $from-huge - 1 !default;
$from-enormous: 1800px !default;
$to-enormous: $from-enormous - 1 !default;
$from-gigantic: 2000px !default;
$to-gigantic: $from-gigantic - 1 !default;
$from-colossal: 2400px !default;
$to-colossal: $from-colossal - 1 !default;
// Grid
// ==========================================================================
$base-column-nb: 12;

View File

@@ -0,0 +1,69 @@
// ==========================================================================
// Settings / Config / Spacings
// ==========================================================================
:root {
--spacing-2xs-mobile: 6;
--spacing-2xs-desktop: 10;
--spacing-xs-mobile: 12;
--spacing-xs-desktop: 16;
--spacing-sm-mobile: 22;
--spacing-sm-desktop: 32;
--spacing-md-mobile: 32;
--spacing-md-desktop: 56;
--spacing-lg-mobile: 48;
--spacing-lg-desktop: 96;
--spacing-xl-mobile: 64;
--spacing-xl-desktop: 128;
--spacing-2xl-mobile: 88;
--spacing-2xl-desktop: 176;
--spacing-3xl-mobile: 122;
--spacing-3xl-desktop: 224;
}
// Spacings
// ==========================================================================
$spacings: (
'gutter': var(--grid-gutter),
'2xs': #{size-clamp('2xs')},
'xs': #{size-clamp('xs')},
'sm': #{size-clamp('sm')},
'md': #{size-clamp('md')},
'lg': #{size-clamp('lg')},
'xl': #{size-clamp('xl')},
'2xl': #{size-clamp('2xl')},
'3xl': #{size-clamp('3xl')},
);
// Function
// ==========================================================================
// Returns spacing.
//
// ```scss
// .c-box {
// margin-top: spacing(gutter);
// }
// ```
//
// @param {string} $key - The spacing key in $spacings.
// @param {number} $multiplier - The multiplier of the spacing value.
// @return {size}
@function spacing($spacing: 'sm', $multiplier: 1) {
@if not map-has-key($spacings, $spacing) {
@error "Unknown master spacing: #{$spacing}";
}
$index: map-get($spacings, $spacing);
@return calc(#{$index} * #{$multiplier});
}

View File

@@ -0,0 +1,38 @@
// ==========================================================================
// Settings / Config / Speeds
// ==========================================================================
// Speeds
// ==========================================================================
$speeds: (
fastest: 0.1s,
faster: 0.15s,
fast: 0.25s,
normal: 0.3s,
slow: 0.5s,
slower: 0.75s,
slowest: 1s,
);
// Function
// ==========================================================================
// Returns timing.
//
// ```scss
// .c-box {
// transition-duration: speed(slow);
// }
// ```
//
// @param {string} $key - The speed key in $speeds.
// @return {duration}
@function speed($key: "normal") {
@if not map-has-key($speeds, $key) {
@error "Unknown '#{$key}' in $speeds.";
}
@return map-get($speeds, $key);
}

View File

@@ -0,0 +1,20 @@
// ==========================================================================
// Settings / Config / CSS VARS
// ==========================================================================
:root {
// Grid
--grid-columns: 4;
--grid-gutter: #{rem(10px)};
--grid-margin: #{rem(10px)};
// Container
--container-width: calc(100% - 2 * var(--grid-margin));
@media (min-width: $from-sm) {
--grid-columns: #{$base-column-nb};
--grid-gutter: #{rem(16px)};
--grid-margin: #{rem(20px)};
}
}

View File

@@ -0,0 +1,44 @@
// ==========================================================================
// Settings / Config / Z-indexes
// ==========================================================================
// Timings
// ==========================================================================
$z-indexes: (
"header": 200,
"above": 1,
"default": 0,
"below": -1
);
// Default z-index for z()
$z-index-default: "above" !default;
// Function
// ==========================================================================
// Retrieves the z-index from the {@see $layers master list}.
//
// @link on http://css-tricks.com/handling-z-index/
//
// @param {string} $layer The name of the z-index.
// @param {number} $modifier A positive or negative modifier to apply
// to the returned z-index value.
// @throw Error if the $layer does not exist.
// @throw Warning if the $modifier might overlap another master z-index.
// @return {number} The computed z-index of $layer and $modifier.
@function z($layer: $z-index-default, $modifier: 0) {
@if not map-has-key($z-indexes, $layer) {
@error "Unknown master z-index layer: #{$layer}";
}
@if ($modifier >= 50 or $modifier <= -50) {
@warn "Modifier may overlap the another master z-index layer: #{$modifier}";
}
$index: map-get($z-indexes, $layer);
@return $index + $modifier;
}

View File

@@ -1,327 +0,0 @@
//
//
// DOCS : https://lukyvj.github.io/family.scss/
//
//
/// Select all children from the first to `$num`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin first($num) {
@if $num == 1 {
&:first-child {
@content;
}
} @else {
&:nth-child(-n + #{$num}) {
@content;
}
}
}
/// Select all children from the last to `$num`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin last($num) {
&:nth-last-child(-n + #{$num}) {
@content;
}
}
/// Select all children after the first to `$num`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin after-first($num) {
&:nth-child(n + #{$num + 1}) {
@content;
}
}
/// Select all children before `$num` from the last.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin from-end($num) {
&:nth-last-child(#{$num}) {
@content;
}
}
/// Select all children between `$first` and `$last`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin between($first, $last) {
&:nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
/// Select all even children between `$first` and `$last`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin even-between($first, $last) {
&:nth-child(even):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
/// Select all odd children between `$first` and `$last`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin odd-between($first, $last) {
&:nth-child(odd):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
/// Select all `$num` children between `$first` and `$last`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin n-between($num, $first, $last) {
&:nth-child(#{$num}n):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
/// Select all children but `$num`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin all-but($num) {
&:not(:nth-child(#{$num})) {
@content;
}
}
/// Select children each `$num`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
/// @alias every
@mixin each($num) {
&:nth-child(#{$num}n) {
@content;
}
}
/// Select children each `$num`.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin every($num) {
&:nth-child(#{$num}n) {
@content;
}
}
/// Select the `$num` child from the start and the `$num` child from the last.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin from-first-last($num) {
&:nth-child(#{$num}),
&:nth-last-child(#{$num}) {
@content;
}
}
/// Select the item in the middle of `$num` child. Only works with odd number
/// chain.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin middle($num) {
&:nth-child(#{round($num / 2)}) {
@content;
}
}
/// Select all children between the `$num` first and the `$num` last.
/// @group with-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - id of the child
@mixin all-but-first-last($num) {
&:nth-child(n + #{$num}):nth-last-child(n + #{$num}) {
@content;
}
}
/// This quantity-query mixin will only select the first of `$limit` items. It will not
/// work if there is not as much as item as you set in `$limit`.
/// @group Quantity queries
/// @param {number} $limit
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin first-of($limit) {
&:nth-last-child(#{$limit}):first-child {
@content;
}
}
/// This quantity-query mixin will only select the last of `$limit` items. It will not
/// if there is not as much as item as you set in `$limit`.
/// @group Quantity queries
/// @param {number} $limit
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin last-of($limit) {
&:nth-of-type(#{$limit}):nth-last-of-type(1) {
@content;
}
}
/// This quantity-query mixin will select every items if there is at least `$num` items. It will not
/// if there is not as much as item as you set in `$num`.
/// @group Quantity queries
/// @param {number} $limit
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin at-least($num) {
$selector: &;
$child: nth(nth($selector, -1), -1);
&:nth-last-child(n + #{$num}),
&:nth-last-child(n + #{$num}) ~ #{$child} {
@content;
}
}
/// This quantity-query mixin will select every items if there is at most `$num` items. It will not
/// if there is not as much as item as you set in `$num`.
/// @group Quantity queries
/// @param {number} $limit
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin at-most($num) {
$selector: &;
$child: nth(nth($selector, -1), -1);
&:nth-last-child(-n + #{$num}):first-child,
&:nth-last-child(-n + #{$num}):first-child ~ #{$child} {
@content;
}
}
/// This quantity-query mixin will select every items only if there is between `$min` and `$max` items.
/// @group Quantity queries
/// @param {number} $limit
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin in-between($min, $max) {
$selector: &;
$child: nth(nth($selector, -1), -1);
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child,
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child ~ #{$child} {
@content;
}
}
/// Select the first exact child
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin first-child() {
&:first-of-type {
@content
}
}
/// Select the last exact child
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin last-child() {
&:last-of-type {
@content
}
}
/// Select all even children.
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin even() {
&:nth-child(even) {
@content;
}
}
/// Select all odd children.
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin odd() {
&:nth-child(odd) {
@content;
}
}
/// Select only the first and last child.
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin first-last() {
&:first-child,
&:last-child {
@content;
}
}
/// Will only select the child if its unique.
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @alias only
@mixin unique() {
&:only-child {
@content;
}
}
/// Will only select the child if its unique.
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin only() {
&:only-child {
@content;
}
}
/// Will only select children if they are not unique. Meaning if there is at
/// least 2 children, the style is applied.
/// @group no-arguments
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin not-unique() {
&:not(:only-child) {
@content;
}
}
/// This mixin is used to automatically sort z-index in numerical order. But it
/// can also sort them in anti-numerical order, depending the parameters you use.
/// @group using functions
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
/// @param {number} $num - Number of children
/// @param {string} $direction [forward] - Direction of the sort
/// @param {number} $index [0] - Index of the sorting
@mixin child-index($num, $direction: 'forward', $index: 0) {
@for $i from 1 through $num {
@if ($direction == 'forward') {
&:nth-child(#{$i}) {
z-index: order-index($i, $index);
@content;
}
} @else if ($direction == 'backward') {
&:nth-last-child(#{$i}) {
z-index: order-index($i, $index);
@content;
}
}
}
}
/// Used by the child-index mixin. It will returned the proper sorted numbers
/// depending on the `$index` value.
/// @access private
/// @param {number} $num - Number of children
/// @param {number} $index - Index of the sorting
@function order-index($i, $index) {
@return ($index + $i);
}

View File

@@ -0,0 +1,352 @@
// ==========================================================================
// Tools / Family
// ==========================================================================
// DOCS : https://lukyvj.github.io/family.scss/
//
// Select all children from the first to `$num`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin first($num) {
@if $num == 1 {
&:first-child {
@content;
}
} @else {
&:nth-child(-n + #{$num}) {
@content;
}
}
}
// Select all children from the last to `$num`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin last($num) {
&:nth-last-child(-n + #{$num}) {
@content;
}
}
// Select all children after the first to `$num`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin after-first($num) {
&:nth-child(n + #{$num + 1}) {
@content;
}
}
// Select all children before `$num` from the last.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin from-end($num) {
&:nth-last-child(#{$num}) {
@content;
}
}
// Select all children between `$first` and `$last`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin between($first, $last) {
&:nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
// Select all even children between `$first` and `$last`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin even-between($first, $last) {
&:nth-child(even):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
// Select all odd children between `$first` and `$last`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin odd-between($first, $last) {
&:nth-child(odd):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
// Select all `$num` children between `$first` and `$last`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin n-between($num, $first, $last) {
&:nth-child(#{$num}n):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
@content;
}
}
// Select all children but `$num`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin all-but($num) {
&:not(:nth-child(#{$num})) {
@content;
}
}
// Select children each `$num`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
// @alias every
@mixin each($num) {
&:nth-child(#{$num}n) {
@content;
}
}
// Select children each `$num`.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin every($num) {
&:nth-child(#{$num}n) {
@content;
}
}
// Select the `$num` child from the start and the `$num` child from the last.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin from-first-last($num) {
&:nth-child(#{$num}),
&:nth-last-child(#{$num}) {
@content;
}
}
// Select the item in the middle of `$num` child. Only works with odd number
// chain.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin middle($num) {
&:nth-child(#{round(math.div($num, 2))}) {
@content;
}
}
// Select all children between the `$num` first and the `$num` last.
// @group with-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - id of the child
@mixin all-but-first-last($num) {
&:nth-child(n + #{$num}):nth-last-child(n + #{$num}) {
@content;
}
}
// This quantity-query mixin will only select the first of `$limit` items. It will not
// work if there is not as much as item as you set in `$limit`.
// @group Quantity queries
// @param {number} $limit
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin first-of($limit) {
&:nth-last-child(#{$limit}):first-child {
@content;
}
}
// This quantity-query mixin will only select the last of `$limit` items. It will not
// if there is not as much as item as you set in `$limit`.
// @group Quantity queries
// @param {number} $limit
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin last-of($limit) {
&:nth-of-type(#{$limit}):nth-last-of-type(1) {
@content;
}
}
// This quantity-query mixin will select every items if there is at least `$num` items. It will not
// if there is not as much as item as you set in `$num`.
// @group Quantity queries
// @param {number} $limit
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin at-least($num) {
$selector: &;
$child: nth(nth($selector, -1), -1);
&:nth-last-child(n + #{$num}),
&:nth-last-child(n + #{$num}) ~ #{$child} {
@content;
}
}
// This quantity-query mixin will select every items if there is at most `$num` items. It will not
// if there is not as much as item as you set in `$num`.
// @group Quantity queries
// @param {number} $limit
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin at-most($num) {
$selector: &;
$child: nth(nth($selector, -1), -1);
&:nth-last-child(-n + #{$num}):first-child,
&:nth-last-child(-n + #{$num}):first-child ~ #{$child} {
@content;
}
}
// This quantity-query mixin will select every items only if there is between `$min` and `$max` items.
// @group Quantity queries
// @param {number} $limit
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin in-between($min, $max) {
$selector: &;
$child: nth(nth($selector, -1), -1);
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child,
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child ~ #{$child} {
@content;
}
}
// Select the first exact child
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin first-child() {
&:first-of-type {
@content
}
}
// Select the last exact child
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin last-child() {
&:last-of-type {
@content
}
}
// Select all even children.
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin even() {
&:nth-child(even) {
@content;
}
}
// Select all odd children.
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin odd() {
&:nth-child(odd) {
@content;
}
}
// Select only the first and last child.
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin first-last() {
&:first-child,
&:last-child {
@content;
}
}
// Will only select the child if its unique.
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @alias only
@mixin unique() {
&:only-child {
@content;
}
}
// Will only select the child if its unique.
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin only() {
&:only-child {
@content;
}
}
// Will only select children if they are not unique. Meaning if there is at
// least 2 children, the style is applied.
// @group no-arguments
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
@mixin not-unique() {
&:not(:only-child) {
@content;
}
}
// This mixin is used to automatically sort z-index in numerical order. But it
// can also sort them in anti-numerical order, depending the parameters you use.
// @group using functions
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
// @param {number} $num - Number of children
// @param {string} $direction [forward] - Direction of the sort
// @param {number} $index [0] - Index of the sorting
@mixin child-index($num, $direction: 'forward', $index: 0) {
@for $i from 1 through $num {
@if ($direction == 'forward') {
&:nth-child(#{$i}) {
z-index: order-index($i, $index);
@content;
}
} @else if ($direction == 'backward') {
&:nth-last-child(#{$i}) {
z-index: order-index($i, $index);
@content;
}
}
}
}
// Used by the child-index mixin. It will returned the proper sorted numbers
// depending on the `$index` value.
// @access private
// @param {number} $num - Number of children
// @param {number} $index - Index of the sorting
@function order-index($i, $index) {
@return ($index + $i);
}

View File

@@ -1,98 +0,0 @@
// ==========================================================================
// Tools / Font Faces
// ==========================================================================
$global-font-file-formats: "woff2", "woff" !default;
//
// Builds the `src` list for an `@font-face` declaration.
//
// @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/utilities/_font-source-declaration.scss
// @link http://goo.gl/Ru1bKP
//
// @param {String} $font-family - The font family name.
// @param {String} $file-path - The path to the font family.
// @param {List} $file-formats - The file formats to request.
// @return {List}
//
// @require {function} list-contains
//
// @access private
//
@function font-source-declaration(
$font-family,
$file-path,
$file-formats
) {
$src: ();
$formats-map: (
eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"),
woff2: "#{$file-path}.woff2" format("woff2"),
woff: "#{$file-path}.woff" format("woff"),
ttf: "#{$file-path}.ttf" format("truetype"),
svg: "#{$file-path}.svg##{$font-family}" format("svg"),
);
@each $key, $values in $formats-map {
@if list-contains($file-formats, $key) {
$file-path: nth($values, 1);
$font-format: nth($values, 2);
$src: append($src, url("#{$assets-path}#{$file-path}") $font-format, comma);
}
}
@return $src;
}
//
// Generates an `@font-face` declaration.
//
// You can choose the specific file formats you need to output; the mixin supports
// `eot`, `ttf`, `svg`, `woff2` and `woff`.
//
// @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/library/_font-face.scss
//
// @param {String} $font-family - The font family name.
// @param {String} $file-path - The path to the font family.
// @param {String|List} $file-formats [("ttf", "woff2", "woff")]
// A list of file formats to support,
// for example ("eot", "ttf", "svg", "woff2", "woff").
//
// @content
// Any additional CSS properties that are included in the `@include`
// directive will be output within the `@font-face` declaration, e.g.
// you can pass in `font-weight`, `font-style` and/or `unicode-range`.
//
// @example scss
// @include font-face(
// "source-sans-pro",
// "fonts/source-sans-pro-regular",
// ("woff2", "woff")
// ) {
// font-style: normal;
// font-weight: 400;
// }
//
// // CSS Output
// @font-face {
// font-family: "source-sans-pro";
// src: url("fonts/source-sans-pro-regular.woff2") format("woff2"),
// url("fonts/source-sans-pro-regular.woff") format("woff");
// font-style: normal;
// font-weight: 400;
// }
//
// @require {function} _font-source-declaration
// @require {function} _retrieve-bourbon-setting
//
@mixin font-face(
$font-family,
$file-path,
$file-formats: $global-font-file-formats
) {
@font-face {
font-family: $font-family;
src: font-source-declaration( $font-family, $file-path, $file-formats);
@content;
}
}

View File

@@ -1,73 +1,53 @@
// ==========================================================================
// Tools / Functions
// ==========================================================================
// Check if the given value is a number in pixel
//
// @param {Number} $number - The value to check
// @return {Boolean}
@function is-pixel-number($number) {
@return type-of($number) == number and unit($number) == "px";
}
// Converts the given pixel value to its EM quivalent.
//
// @param {Number} $size - The pixel value to convert.
// @param {Number} $base [$font-size] - The assumed base font size.
// @return {Number} Scalable pixel value in EMs.
//
@function em($size, $base: $font-size) {
@if (type-of($size) == number) {
@if (unit($size) != "px") {
@error "`#{$size}` needs to be a pixel value.";
}
} @else {
@error "`#{$size}` needs to be a number.";
@if not is-pixel-number($size) {
@error "`#{$size}` needs to be a number in pixel.";
}
@if (type-of($base) == number) {
@if (unit($base) != "px") {
@error "`#{$base}` needs to be a pixel value.";
}
} @else {
@error "`#{$base}` needs to be a number.";
@if not is-pixel-number($base) {
@error "`#{$base}` needs to be a number in pixel.";
}
@return ($size / $base) * 1em;
@return math.div($size, $base) * 1em;
}
//
// Converts the given pixel value to its REM quivalent.
//
// @param {Number} $size - The pixel value to convert.
// @param {Number} $base [$font-size] - The assumed base font size.
// @return {Number} Scalable pixel value in REMs.
//
@function rem($size, $base: $font-size) {
@if (type-of($size) == number) {
@if (unit($size) != "px") {
@error "`#{$size}` needs to be a pixel value.";
}
} @else {
@error "`#{$size}` needs to be a number.";
@if not is-pixel-number($size) {
@error "`#{$size}` needs to be a number in pixel.";
}
@if (type-of($base) == number) {
@if (unit($base) != "px") {
@error "`#{$base}` needs to be a pixel value.";
}
} @else {
@error "`#{$base}` needs to be a number.";
@if not is-pixel-number($base) {
@error "`#{$base}` needs to be a number in pixel.";
}
@return ($size / $base) * 1rem;
@return math.div($size, $base) * 1rem;
}
//
// Converts a number to a percentage.
//
// @alias percentage()
// @link http://sassdoc.com/annotations/#alias
// @param {Number} $number - The value to convert.
// @return {Number} A percentage.
//
@function span($number) {
@return percentage($number);
}
//
// Checks if a list contains a value(s).
//
// @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/validators/_contains.scss
@@ -75,7 +55,7 @@
// @param {List} $values - A single value or list of values to check for.
// @return {Boolean}
// @access private
//
@function list-contains(
$list,
$values...
@@ -89,40 +69,146 @@
@return true;
}
//
// Resolve whether a rule is important or not.
//
// @param {Boolean} $flag - Whether a rule is important (TRUE) or not (FALSE).
// @return {String|Null} Returns `!important` or NULL.
//
@function important($flag: false) {
@if ($flag == true) {
@return !important;
} @elseif ($important == false) {
} @else if ($important == false) {
@return null;
} @else {
@error "`#{$flag}` needs to be `true` or `false`."
@error "`#{$flag}` needs to be `true` or `false`.";
}
}
//
// Determine if the current context is for a WYSIWYG editor.
//
// @requires {String} $context - The global context of the stylesheet.
// @return {Boolean} If the $context is set to "editor".
//
@function is-editor() {
@return ('editor' == $context);
}
//
// Determine if the current context is for the front-end.
//
// @requires {String} $context - The global context of the stylesheet.
// @return {Boolean} If the $context is set to "frontend".
//
@function is-frontend() {
@return ('frontend' == $context);
}
$context: 'frontend' !default;
// Returns calculation of a percentage of the grid cell width
// with optional inset of grid gutter.
//
// ```scss
// .c-box {
// width: grid-space(6/12);
// margin-left: grid-space(1/12, 1);
// }
// ```
//
// @param {number} $percentage - The percentage spacer
// @param {number} $inset - The grid gutter inset
// @return {function<number>}
@function grid-space($percentage, $inset: 0) {
@return calc(#{$percentage} * (#{vw(100)} - 2 * var(--grid-margin, 0px)) - (1 - #{$percentage}) * var(--grid-gutter, 0px) + #{$inset} * var(--grid-gutter, 0px));
}
// Returns calculation of a percentage of the viewport small height.
//
// ```scss
// .c-box {
// height: svh(100);
// }
// ```
//
// @param {number} $number - The percentage number
// @return {function<number>} in svh
@function svh($number) {
@return calc(#{$number} * var(--svh, 1svh));
}
// Returns calculation of a percentage of the viewport large height.
//
// ```scss
// .c-box {
// height: lvh(100);
// }
// ```
//
// @param {number} $number - The percentage number
// @return {function<number>} in lvh
@function lvh($number) {
@return calc(#{$number} * var(--lvh, 1lvh));
}
// Returns calculation of a percentage of the viewport dynamic height.
//
// ```scss
// .c-box {
// height: dvh(100);
// }
// ```
//
// @param {number} $number - The percentage number
// @return {function<number>} in dvh
@function dvh($number) {
@return calc(#{$number} * var(--dvh, 1dvh));
}
// Returns calculation of a percentage of the viewport width.
//
// ```scss
// .c-box {
// width: vw(100);
// }
// ```
//
// @param {number} $number - The percentage number
// @return {function<number>} in vw
@function vw($number) {
@return calc(#{$number} * var(--vw, 1vw));
}
@function clamp-with-max($min, $size, $max) {
$vw-context: $vw-viewport * 0.01;
@return clamp(#{$min}, calc(#{$size} / #{$vw-context} * 1vw), #{$max});
}
@function size-clamp($size) {
@return clamp-with-max(
calc(#{rem(1px)} * var(--spacing-#{$size}-mobile)),
var(--spacing-#{$size}-desktop),
calc(#{rem(1px)} * var(--spacing-#{$size}-desktop))
);
}
// Returns clamp of calculated preferred responsive font size
// within a font size and breakpoint range.
//
// ```scss
// .c-heading.-h1 {
// font-size: responsive-value(30px, 60px, 1800);
// }
//
// .c-heading.-h2 {
// font-size: responsive-value(20px, 40px, $from-xl);
// }
// ```
//
// @param {number} $min-size - Minimum font size in pixels.
// @param {number} $max-size - Maximum font size in pixels.
// @param {number} $breakpoint - Maximum breakpoint.
// @return {function<number, function<number>, number>}
@function responsive-value($min-size, $max-size, $breakpoint) {
$delta: math.div($max-size, $breakpoint);
@return clamp($min-size, calc(#{strip-unit($delta)} * #{vw(100)}), $max-size);
}

View File

@@ -2,7 +2,6 @@
// Tools / Layout
// ==========================================================================
//
// Grid-like layout system.
//
// The layout tools provide a column-style layout system. This file contains
@@ -10,7 +9,6 @@
//
// @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss
//
//
// Generate the layout container.
//
@@ -19,9 +17,11 @@
//
// @requires {function} u-list-reset
// @output `font-size`, `margin`, `padding`, `list-style`
//
@mixin o-layout($gutter: 0, $fix-whitespace: true) {
@include u-list-reset;
margin: 0;
padding: 0;
list-style: none;
@if ($fix-whitespace) {
font-size: 0;
@@ -32,7 +32,6 @@
}
}
//
// Generate the layout item.
//
// 1. Required in order to combine fluid widths with fixed gutters.
@@ -43,7 +42,7 @@
// 4. By default, all layout items are full-width (mobile first).
// 5. Gutters provided by left padding:
// http://csswizardry.com/2011/08/building-better-grid-systems/
//
@mixin o-layout_item($gutter: 0, $fix-whitespace: true) {
display: inline-block; // [2]
width: 100%; // [4]

View File

@@ -0,0 +1,141 @@
// ==========================================================================
// Tools / Maths
// ==========================================================================
// Remove the unit of a length
//
// @param {Number} $number Number to remove unit from
// @return {function<number>}
@function strip-unit($value) {
@if type-of($value) != "number" {
@error "Invalid `#{type-of($value)}` type. Choose a number type instead.";
} @else if type-of($value) == "number" and not is-unitless($value) {
@return math.div($value, $value * 0 + 1);
}
@return $value;
}
// Returns the square root of the given number.
//
// @param {number} $number The number to calculate.
// @return {number}
@function sqrt($number) {
$x: 1;
$value: $x;
@for $i from 1 through 10 {
$value: $x - math.div(($x * $x - abs($number)), (2 * $x));
$x: $value;
}
@return $value;
}
// Returns a number raised to the power of an exponent.
//
// @param {number} $number The base number.
// @param {number} $exp The exponent.
// @return {number}
@function pow($number, $exp) {
$value: 1;
@if $exp > 0 {
@for $i from 1 through $exp {
$value: $value * $number;
}
} @else if $exp < 0 {
@for $i from 1 through -$exp {
$value: math.div($value, $number);
}
}
@return $value;
}
// Returns the factorial of the given number.
//
// @param {number} $number The number to calculate.
// @return {number}
@function fact($number) {
$value: 1;
@if $number > 0 {
@for $i from 1 through $number {
$value: $value * $i;
}
}
@return $value;
}
// Returns an approximation of pi, with 11 decimals.
//
// @return {number}
@function pi() {
@return 3.14159265359;
}
// Converts the number in degrees to the radian equivalent .
//
// @param {number} $angle The angular value to calculate.
// @return {number} If $angle has the `deg` unit,
// the radian equivalent is returned.
// Otherwise, the unitless value of $angle is returned.
@function rad($angle) {
$unit: unit($angle);
$angle: strip-units($angle);
// If the angle has `deg` as unit, convert to radians.
@if ($unit == deg) {
@return math.div($angle, 180) * pi();
}
@return $angle;
}
// Returns the sine of the given number.
//
// @param {number} $angle The angle to calculate.
// @return {number}
@function sin($angle) {
$sin: 0;
$angle: rad($angle);
@for $i from 0 through 10 {
$sin: $sin + pow(-1, $i) * math.div(pow($angle, (2 * $i + 1)), fact(2 * $i + 1));
}
@return $sin;
}
// Returns the cosine of the given number.
//
// @param {string} $angle The angle to calculate.
// @return {number}
@function cos($angle) {
$cos: 0;
$angle: rad($angle);
@for $i from 0 through 10 {
$cos: $cos + pow(-1, $i) * math.div(pow($angle, 2 * $i), fact(2 * $i));
}
@return $cos;
}
// Returns the tangent of the given number.
//
// @param {string} $angle The angle to calculate.
// @return {number}
@function tan($angle) {
@return math.div(sin($angle), cos($angle));
}

View File

@@ -2,37 +2,34 @@
// Tools / Mixins
// ==========================================================================
//
// Set the color of the highlight that appears over a link while it's being tapped.
//
// By default, the highlight is suppressed.
//
// @param {Color} $value [rgba(0, 0, 0, 0)] - The value of the highlight.
// @output `-webkit-tap-highlight-color`
//
@mixin tap-highlight-color($value: rgba(0, 0, 0, 0)) {
-webkit-tap-highlight-color: $value;
}
//
// Set whether or not touch devices use momentum-based scrolling for the given element.
//
// By default, applies momentum-based scrolling for the current element.
//
// @param {String} $value [rgba(0, 0, 0, 0)] - The type of scrolling.
// @output `-webkit-overflow-scrolling`
//
@mixin overflow-scrolling($value: touch) {
-webkit-overflow-scrolling: $value;
}
//
// Micro clearfix rules for containing floats.
//
// @link http://www.cssmojo.com/the-very-latest-clearfix-reloaded/
// @param {List} $supports The type of clearfix to generate.
// @output Injects `:::after` pseudo-element.
//
@mixin u-clearfix($supports...) {
&::after {
display: if(list-contains($supports, table), table, block);
@@ -41,7 +38,6 @@
}
}
//
// Generate a font-size and baseline-compatible line-height.
//
// @link https://github.com/inuitcss/inuitcss/c14029c/tools/_tools.font-size.scss
@@ -49,25 +45,24 @@
// @param {Number} $line-height [auto] - The line box height.
// @param {Boolean} $important [false] - Whether the font-size is important.
// @output `font-size`, `line-height`
//
@mixin font-size($font-size, $line-height: auto, $important: false) {
$important: important($important);
font-size: rem($font-size) $important;
@if ($line-height == "auto") {
line-height: ceil($font-size / $line-height) * ($line-height / $font-size) $important;
line-height: ceil(math.div($font-size, $line-height)) * math.div($line-height, $font-size) $important;
}
@else {
@if (type-of($line-height) == number or $line-height == "inherit" or $line-height == "normal") {
line-height: $line-height $important;
}
@elseif ($line-height != "none" and $line-height != false) {
@error "Doh! `#{$line-height}` is not a valid value for `$line-height`."
@else if ($line-height != "none" and $line-height != false) {
@error "Doh! `#{$line-height}` is not a valid value for `$line-height`.";
}
}
}
//
// Vertically-center the direct descendants of the current element.
//
// Centering is achieved by displaying children as inline-blocks. Any whitespace
@@ -75,7 +70,7 @@
// and its children.
//
// @output `font-size`, `display`, `vertical-align`
//
@mixin o-vertical-center {
font-size: 0;
@@ -93,13 +88,12 @@
}
}
//
// Generate `:hover` and `:focus` styles in one go.
//
// @link https://github.com/inuitcss/inuitcss/blob/master/tools/_tools.mixins.scss
// @content Wrapped in `:focus` and `:hover` pseudo-classes.
// @output Wraps the given content in `:focus` and `:hover` pseudo-classes.
//
@mixin u-hocus {
&:focus,
&:hover {
@@ -107,13 +101,12 @@
}
}
//
// Generate `:active` and `:focus` styles in one go.
//
// @see {Mixin} u-hocus
// @content Wrapped in `:focus` and `:active` pseudo-classes.
// @output Wraps the given content in `:focus` and `:hover` pseudo-classes.
//
@mixin u-actus {
&:focus,
&:active {
@@ -121,18 +114,6 @@
}
}
//
// Injects generic rules for disabling UL/OL/LI styles.
//
// @output `list-style`, `margin`, `padding`
//
@mixin u-list-reset {
margin: 0;
padding: 0;
list-style: none;
}
//
// Prevent text from wrapping onto multiple lines for the current element.
//
// An ellipsis is appended to the end of the line.
@@ -142,7 +123,7 @@
//
// @param {Number} $width [100%] - The maximum width of element.
// @output `max-width`, `word-wrap`, `white-space`, `overflow`, `text-overflow`
//
@mixin u-truncate($width: 100%) {
overflow: hidden;
text-overflow: ellipsis;
@@ -153,12 +134,11 @@
}
}
//
// Applies accessible hiding to the current element.
//
// @param {Boolean} $important [true] - Whether the visibility is important.
// @output Properties for removing the element from the document flow.
//
@mixin u-accessibly-hidden($important: true) {
$important: important($important);
position: absolute $important;
@@ -171,12 +151,11 @@
border: 0;
}
//
// Allows an accessibly hidden element to be focusable via keyboard navigation.
//
// @content For styling the now visible element.
// @output Injects `:focus`, `:active` pseudo-classes.
//
@mixin u-accessibly-focusable {
@include u-actus {
clip: auto;
@@ -187,7 +166,6 @@
}
}
//
// Hide the current element from all.
//
// The element will be hidden from screen readers and removed from the document flow.
@@ -195,14 +173,13 @@
// @link http://juicystudio.com/article/screen-readers-display-none.php
// @param {Boolean} $important [true] - Whether the visibility is important.
// @output `display`, `visibility`
//
@mixin u-hidden($important: true) {
$important: important($important);
display: none $important;
visibility: hidden $important;
}
//
// Show the current element for all.
//
// The element will be accessible from screen readers and visible in the document flow.
@@ -210,9 +187,38 @@
// @param {String} $display [block] - The rendering box used for the element.
// @param {Boolean} $important [true] - Whether the visibility is important.
// @output `display`, `visibility`
//
@mixin u-shown($display: block, $important: true) {
$important: important($important);
display: $display $important;
visibility: visible $important;
}
// Aspect-ratio polyfill
//
// @param {Number} $ratio [19/6] - The ratio of the element.
// @param {Number} $width [100%] - The fallback width of element.
// @param {Boolean} $children [false] - Whether the element contains children for the fallback properties.
// @output Properties for maintaining aspect-ratio
@mixin aspect-ratio($ratio: math.div(16, 9), $width: 100%, $children: false) {
@supports (aspect-ratio: 1) {
aspect-ratio: $ratio;
}
@supports not (aspect-ratio: 1) {
height: 0;
padding-top: calc(#{$width} * #{math.div(1, $ratio)});
@if ($children == true) {
position: relative;
> * {
position: absolute;
top: 0;
left: 0;
}
}
}
}

View File

@@ -1,76 +0,0 @@
// ==========================================================================
// Tools / Ratio Constraint
// ==========================================================================
//
// A tool to restrain a container to a unitary or fractional proportion.
//
$data-ratios: "1/2" "0.5" 50%,
"11/20" "0.55" 55%,
"3/5" "0.6" 60%,
"13/20" "0.65" 65%,
"7/10" "0.7" 70%,
"3/4" "0.75" 75%,
"4/5" "0.8" 80%,
"17/20" "0.85" 85%,
"9/10" "0.9" 90%,
"19/20" "0.95" 95%,
"1/1" "1" 100%,
"21/20" "1.05" 105%,
"11/10" "1.1" 110%,
"23/20" "1.15" 115%,
"6/5" "1.2" 120%,
"5/4" "1.25" 125% !default;
$data-ratio-crops: "top" "bottom" "both" !default;
@mixin crop($crop) {
@if $crop == "top" {
bottom: 0;
} @else if $crop == "bottom" {
top: 0;
} @else if $crop == "both" {
top: 50%;
transform: translateY(-50%);
}
}
.u-ratio {
position: relative;
overflow: hidden;
&::before {
display: block;
width: 100%;
content: "";
}
@each $ratio in $data-ratios {
$ratio-1: nth($ratio, 1);
$ratio-2: nth($ratio, 2);
&[data-ratio="#{$ratio-1}"]::before,
&[data-ratio="#{$ratio-2}"]::before {
padding-top: nth($ratio, 3);
}
}
}
.u-ratio_content_container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
}
.u-ratio_content {
position: absolute;
width: 100%;
@each $crop in $data-ratio-crops {
&[data-ratio-crop="#{$crop}"] {
@include crop($crop);
}
}
}

View File

@@ -10,19 +10,21 @@
// .u-pull-2/4
// .u-pull-1/5
// .u-push-2/3
$widths-offsets: false !default;
// By default, the boilerplate uses fractions-like classes like `<div class="u-1/4">`.
// You can change the `/` to whatever you fancy with this variable.
$fractions-delimiter: \/ !default;
// When using Sass-MQ, this defines the separator for the breakpoints suffix
// in the class name. By default, we are generating the responsive suffixes
// for the classes with a `@` symbol so you get classes like:
// <div class="u-3/12@mobile">
$breakpoint-delimiter: \@ !default;
//
// Generate a series of width helper classes
//
// @example scss
@@ -45,7 +47,7 @@ $breakpoint-delimiter: \@ !default;
// @param {List} $colums - The columns we want the widths to have.
// @param {String} $breakpoint - Optional suffix for responsive widths.
// @output `width`, `position`, `right`, `left`
//
@mixin widths($columns, $breakpoint: null, $important: true) {
$important: important($important);
@@ -56,7 +58,7 @@ $breakpoint-delimiter: \@ !default;
@for $numerator from 1 through $denominator {
// Build a class in the format `.u-3/4[@<breakpoint>]`.
.u-#{$numerator}#{$fractions-delimiter}#{$denominator}#{$breakpoint} {
width: ($numerator / $denominator) * 100% $important;
width: math.div($numerator, $denominator) * 100% $important;
}
@if ($widths-offsets == true) {
@@ -64,13 +66,13 @@ $breakpoint-delimiter: \@ !default;
.u-push-#{$numerator}#{$fractions-delimiter}#{$denominator}#{$breakpoint} {
position: relative $important;
right: auto $important;
left: ($numerator / $denominator) * 100% $important;
left: math.div($numerator, $denominator) * 100% $important;
}
// Build a class in the format `.u-pull-5/6[@<breakpoint>]`.
.u-pull-#{$numerator}#{$fractions-delimiter}#{$denominator}#{$breakpoint} {
position: relative $important;
right: ($numerator / $denominator) * 100% $important;
right: math.div($numerator, $denominator) * 100% $important;
left: auto $important;
}
}

View File

@@ -4,6 +4,7 @@
// Floats
// ==========================================================================
.u-float-left {
float: left !important;
}
@@ -14,6 +15,7 @@
// Horizontal Text
// ==========================================================================
.u-text-center {
text-align: center !important;
}
@@ -28,6 +30,7 @@
// Vertical Text
// ==========================================================================
.u-align-baseline {
vertical-align: baseline !important;
}

View File

@@ -0,0 +1,43 @@
// ==========================================================================
// Tools / Grid Columns
// ==========================================================================
//
// Grid layout system.
//
// This tool generates columns for all needed media queries.
// Unused classes will be purge by the css post-processor.
//
$colsMax: $base-column-nb + 1;
@each $breakpoint, $mediaquery in $breakpoints {
@for $fromIndex from 1 through $colsMax {
@for $toIndex from 1 through $colsMax {
// Columns without media query
@if $breakpoint == "tiny" {
.u-gc-#{$fromIndex}\/#{$toIndex} {
--gc-start: #{$fromIndex};
--gc-end: #{$toIndex};
}
}
// Columns min-width breakpoints `@from-*`
.u-gc-#{$fromIndex}\/#{$toIndex}\@from-#{$breakpoint} {
@media #{mq-min($breakpoint)} {
--gc-start: #{$fromIndex};
--gc-end: #{$toIndex};
}
}
// Columns max-width breakpoints @to-*`
.u-gc-#{$fromIndex}\/#{$toIndex}\@to-#{$breakpoint} {
@media #{mq-max($breakpoint)} {
--gc-start: #{$fromIndex};
--gc-end: #{$toIndex};
}
}
}
}
}

View File

@@ -1,40 +0,0 @@
// ==========================================================================
// Utilities / Headings
// ==========================================================================
/**
* Redefine all of our basic heading styles against utility classes so as to
* provide larger (or smaller) generic font sizes. Anything more opinionated
* than simple font-size changes should likely be applied via "o-" classes
*
* @example
* <p class="u-h1"></p>
*
* @requires base/headings
* @link http://csswizardry.com/2016/02/managing-typography-on-large-apps/
* @link https://github.com/inuitcss/inuitcss/blob/develop/utilities/_utilities.headings.scss
*/
.u-h1 {
font-size: rem($font-size-h1) !important;
}
.u-h2 {
font-size: rem($font-size-h2) !important;
}
.u-h3 {
font-size: rem($font-size-h3) !important;
}
.u-h4 {
font-size: rem($font-size-h4) !important;
}
.u-h5 {
font-size: rem($font-size-h5) !important;
}
.u-h6 {
font-size: rem($font-size-h6) !important;
}

View File

@@ -4,18 +4,21 @@
// Layout
// ==========================================================================
.u-clearfix {
@include u-clearfix;
}
// Decorative
// =============================================================================
.u-truncate {
@include u-truncate;
}
// Visibility / Display
// ==========================================================================
[hidden][aria-hidden="false"] {
position: absolute;
display: inherit;
@@ -30,35 +33,33 @@
// display: block;
// }
// /**
// * 1. Fix for Firefox bug: an image styled `max-width:100%` within an
// * inline-block will display at its default size, and not limit its width to
// * 100% of an ancestral container.
// */
// // 1. Fix for Firefox bug: an image styled `max-width:100%` within an
// // inline-block will display at its default size, and not limit its width to
// // 100% of an ancestral container.
//
// .u-inline-block {
// display: inline-block !important;
// max-width: 100%; /* 1 */
// }
//
// .u-inline {
// display: inline !important;
// }
//
// .u-table {
// display: table !important;
// }
//
// .u-tableCell {
// display: table-cell !important;
// }
//
// .u-tableRow {
// display: table-row !important;
// }
/**
* Completely remove from the flow but leave available to screen readers.
*/
// Completely remove from the flow but leave available to screen readers.
.u-screen-reader-text {
@include u-accessibly-hidden;
}
@@ -69,13 +70,12 @@
}
}
/*
* Extends the `.screen-reader-text` class to allow the element
* to be focusable when navigated to via the keyboard.
*
* @link https://www.drupal.org/node/897638
* @todo Define styles when focused.
*/
// Extends the `.screen-reader-text` class to allow the element
// to be focusable when navigated to via the keyboard.
//
// @link https://www.drupal.org/node/897638
// @todo Define styles when focused.
.u-screen-reader-text.-focusable {
@include u-accessibly-focusable;
}

View File

@@ -11,9 +11,9 @@
////
@media print {
/**
* 1. Black prints faster: http://www.sanbeiji.com/archives/953
*/
// 1. Black prints faster: http://www.sanbeiji.com/archives/953
*,
*:before,
*:after,
@@ -21,7 +21,7 @@
*:first-line {
background: transparent !important;
box-shadow: none !important;
color: #000000 !important; /* [1] */
color: #000000 !important; // [1]
text-shadow: none !important;
}
@@ -38,10 +38,9 @@
content: " (" attr(title) ")";
}
/**
* Don't show links that are fragment identifiers, or use the `javascript:`
* pseudo protocol.
*/
// Don't show links that are fragment identifiers, or use the `javascript:`
// pseudo protocol.
a[href^="#"]:after,
a[href^="javascript:"]:after {
content: "";
@@ -53,9 +52,8 @@
page-break-inside: avoid;
}
/**
* Printing Tables: http://css-discuss.incutio.com/wiki/Printing_Tables
*/
// Printing Tables: http://css-discuss.incutio.com/wiki/Printing_Tables
thead {
display: table-header-group;
}

View File

@@ -0,0 +1,37 @@
// ==========================================================================
// Utilities / Ratio
// ==========================================================================
// @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.ratio.scss
// A list of aspect ratios that get generated as modifier classes.
$aspect-ratios: (
(2:1),
(4:3),
(16:9),
) !default;
/* stylelint-disable */
// Generate a series of ratio classes to be used like so:
//
// @example
// <div class="o-ratio u-16:9">
@each $ratio in $aspect-ratios {
@each $antecedent, $consequent in $ratio {
@if (type-of($antecedent) != number) {
@error "`#{$antecedent}` needs to be a number."
}
@if (type-of($consequent) != number) {
@error "`#{$consequent}` needs to be a number."
}
.u-#{$antecedent}\:#{$consequent}::before {
padding-bottom: math.div($consequent, $antecedent) * 100%;
}
}
}
/* stylelint-enable */

View File

@@ -8,12 +8,11 @@
///
/// @example
/// .u-margin-top {}
/// .u-padding-left-large {}
/// .u-margin-right-small {}
/// .u-margin-top-xs {}
/// .u-padding-left-lg {}
/// .u-margin-right-sm {}
/// .u-padding {}
/// .u-padding-right-none {}
/// .u-padding-horizontal {}
/// .u-padding-vertical-small {}
///
/// @link https://github.com/inuitcss/inuitcss/blob/512977a/utilities/_utilities.spacing.scss
////
@@ -26,8 +25,8 @@ $spacing-directions: (
'-right': '-right',
'-bottom': '-bottom',
'-left': '-left',
'-horizontal': '-left' '-right',
'-vertical': '-top' '-bottom',
'-x': '-left' '-right',
'-y': '-top' '-bottom',
) !default;
$spacing-properties: (
@@ -35,18 +34,47 @@ $spacing-properties: (
'margin': 'margin',
) !default;
$spacing-sizes: (
null: $unit,
'-small': $unit-small,
'-none': 0
) !default;
$spacing-sizes: join($spacings, (
null: var(--grid-gutter),
'none': 0
));
@each $property-namespace, $property in $spacing-properties {
@each $direction-namespace, $direction-rules in $spacing-directions {
@each $size-namespace, $size in $spacing-sizes {
.u-#{$property-namespace}#{$direction-namespace}#{$size-namespace} {
@each $direction in $direction-rules {
#{$property}#{$direction}: $size !important;
@each $breakpoint, $mediaquery in $breakpoints {
@each $property-namespace, $property in $spacing-properties {
@each $direction-namespace, $directions in $spacing-directions {
@each $size-namespace, $size in $spacing-sizes {
// Prepend "-" to spacing sizes if not null
$size-namespace: if($size-namespace != null, "-" + $size-namespace, $size-namespace);
// Base class
$base-class: ".u-" + #{$property-namespace}#{$direction-namespace}#{$size-namespace};
// Spacing without media query
@if $breakpoint == "xs" {
#{$base-class} {
@each $direction in $directions {
#{$property}#{$direction}: $size !important;
}
}
}
// Spacing min-width breakpoints `@from-*`
#{$base-class}\@from-#{$breakpoint} {
@media #{mq-min($breakpoint)} {
@each $direction in $directions {
#{$property}#{$direction}: $size !important;
}
}
}
// Spacing max-width breakpoints @to-*`
#{$base-class}\@to-#{$breakpoint} {
@media #{mq-max($breakpoint)} {
@each $direction in $directions {
#{$property}#{$direction}: $size !important;
}
}
}
}
}

View File

@@ -2,9 +2,8 @@
// Utilities / States
// ==========================================================================
/**
* ARIA roles display visual cursor hints
*/
// ARIA roles display visual cursor hints
[aria-busy="true"] {
cursor: progress;
}
@@ -17,9 +16,7 @@
cursor: default;
}
/**
* Control visibility without affecting flow.
*/
// Control visibility without affecting flow.
.is-visible {
visibility: visible !important;
@@ -31,9 +28,7 @@
opacity: 0 !important;
}
/**
* Completely remove from the flow and screen readers.
*/
// Completely remove from the flow and screen readers.
.is-hidden {
@include u-hidden;
@@ -51,34 +46,32 @@
}
}
// .is-hidden\@to-large {
// @media (max-width: $to-large) {
// .is-hidden\@to-lg {
// @media (max-width: $to-lg) {
// display: none;
// }
// }
//
// .is-hidden\@from-lg {
// @media (min-width: $from-lg) {
// display: none;
// }
// }
// .is-hidden\@from-large {
// @media (min-width: $from-large) {
// display: none;
// }
// }
// /**
// * Display a hidden-by-default element.
// */
// // Display a hidden-by-default element.
//
// .is-shown {
// @include u-shown;
// }
//
// table.is-shown {
// display: table !important;
// }
//
// tr.is-shown {
// display: table-row !important;
// }
//
// td.is-shown,
// th.is-shown {
// display: table-cell !important;

View File

@@ -4,8 +4,8 @@
////
/// @link https://github.com/inuitcss/inuitcss/blob/6eb574f/utilities/_utilities.widths.scss
////
///
///
/// Which fractions would you like in your grid system(s)?
/// By default, the boilerplate provides fractions of one whole, halves, thirds,
/// quarters, and fifths, e.g.:
@@ -15,6 +15,14 @@
/// .u-2/5
/// .u-3/4
/// .u-2/3
////
$widths-fractions: 1 2 3 4 5 !default;
@include widths($widths-fractions);
.u-1\/2\@from-sm {
@media (min-width: $from-sm) {
width: 50%;
}
}

11
build/build.js Normal file
View File

@@ -0,0 +1,11 @@
import concatFiles from './tasks/concats.js';
import compileScripts from './tasks/scripts.js';
import compileStyles from './tasks/styles.js';
import compileSVGs from './tasks/svgs.js';
import bumpVersions from './tasks/versions.js';
concatFiles();
compileScripts();
compileStyles();
compileSVGs();
bumpVersions();

View File

@@ -1,14 +0,0 @@
import gulp from 'gulp';
import gulpConcat from 'gulp-concat';
import paths from '../mconfig.json';
function concat() {
return gulp
.src([
`${paths.scripts.vendors.src}*.js`
])
.pipe(gulpConcat(`${paths.scripts.vendors.main}.js`))
.pipe(gulp.dest(paths.scripts.dest));
}
export default concat;

View File

@@ -1,14 +0,0 @@
import gulp from 'gulp';
import paths from '../mconfig.json';
import error from './error.js';
function copy() {
return gulp
.src([`./node_modules/locomotive-scroll/assets/scripts/scroll/vendors/*`])
.on('error', function(err) {
error(this, err);
})
.pipe(gulp.dest(`${paths.scripts.src}/scroll/vendors`));
}
export default copy;

25
build/helpers/config.js Normal file
View File

@@ -0,0 +1,25 @@
/**
* @file Provides simple user configuration options.
*/
import loconfig from '../../loconfig.json' assert { type: 'json' };
import { merge } from '../utils/index.js';
let usrconfig;
try {
usrconfig = await import('../../loconfig.local.json', {
assert: { type: 'json' },
});
usrconfig = usrconfig.default;
merge(loconfig, usrconfig);
} catch (err) {
// do nothing
}
export default loconfig;
export {
loconfig,
};

162
build/helpers/glob.js Normal file
View File

@@ -0,0 +1,162 @@
/**
* @file Retrieve the first available glob library.
*
* Note that options vary between libraries.
*
* Candidates:
*
* - {@link https://npmjs.com/package/tiny-glob tiny-glob} [1][5][6]
* - {@link https://npmjs.com/package/globby globby} [2][5]
* - {@link https://npmjs.com/package/fast-glob fast-glob} [3]
* - {@link https://npmjs.com/package/glob glob} [1][4][5]
*
* Notes:
*
* - [1] The library's function accepts only a single pattern.
* - [2] The library's function accepts only an array of patterns.
* - [3] The library's function accepts either a single pattern
* or an array of patterns.
* - [4] The library's function does not return a Promise but will be
* wrapped in a function that does return a Promise.
* - [5] The library's function will be wrapped in a function that
* supports a single pattern and an array of patterns.
* - [6] The library's function returns files and directories but will be
* preconfigured to return only files.
*/
import { promisify } from 'node:util';
/**
* @callback GlobFn
*
* @param {string|string[]} patterns - A string pattern
* or an array of string patterns.
* @param {object} options
*
* @returns {Promise<string[]>}
*/
/**
* @typedef {object} GlobOptions
*/
/**
* @type {GlobFn|undefined} The discovered glob function.
*/
let glob;
/**
* @type {string[]} A list of packages to attempt import.
*/
const candidates = [
'tiny-glob',
'globby',
'fast-glob',
'glob',
];
try {
glob = await importGlob();
} catch (err) {
// do nothing
}
/**
* @type {boolean} Whether a glob function was discovered (TRUE) or not (FALSE).
*/
const supportsGlob = (typeof glob === 'function');
/**
* Imports the first available glob function.
*
* @throws {TypeError} If no glob library was found.
*
* @returns {GlobFn}
*/
async function importGlob() {
for (let name of candidates) {
try {
let globModule = await import(name);
if (typeof globModule.default !== 'function') {
throw new TypeError(`Expected ${name} to be a function`);
}
/**
* Wrap the function to ensure
* a common pattern.
*/
switch (name) {
case 'tiny-glob':
/** [1][5] */
return createArrayableGlob(
/** [6] */
createPresetGlob(globModule.default, {
filesOnly: true
})
);
case 'globby':
/** [2][5] - If `patterns` is a string, wraps into an array. */
return (patterns, options) => globModule.default([].concat(patterns), options);
case 'glob':
/** [1][5] */
return createArrayableGlob(
/** [4] */
promisify(globModule.default)
);
default:
return globModule.default;
}
} catch (err) {
// swallow this error; skip to the next candidate.
}
}
throw new TypeError(
`No glob library was found, expected one of: ${candidates.join(', ')}`
);
}
/**
* Creates a wrapper function for the glob function
* to provide support for arrays of patterns.
*
* @param {function} globFn - The glob function.
*
* @returns {GlobFn}
*/
function createArrayableGlob(globFn) {
return (patterns, options) => {
/** [2] If `patterns` is a string, wraps into an array. */
patterns = [].concat(patterns);
const globs = patterns.map((pattern) => globFn(pattern, options));
return Promise.all(globs).then((files) => {
return [].concat.apply([], files);
});
};
}
/**
* Creates a wrapper function for the glob function
* to define new default options.
*
* @param {function} globFn - The glob function.
* @param {GlobOptions} presets - The glob function options to preset.
*
* @returns {GlobFn}
*/
function createPresetGlob(globFn, presets) {
return (patterns, options) => globFn(patterns, Object.assign({}, presets, options));
}
export default glob;
export {
glob,
supportsGlob,
};

61
build/helpers/message.js Normal file
View File

@@ -0,0 +1,61 @@
/**
* @file Provides a decorator for console messages.
*/
import kleur from 'kleur';
/**
* Outputs a message to the console.
*
* @param {string} text - The message to output.
* @param {string} [type] - The type of message.
* @param {string} [timerID] - The console time label to output.
*/
function message(text, type, timerID) {
switch (type) {
case 'success':
console.log('✅ ', kleur.bgGreen().black(text));
break;
case 'chore':
console.log('🧹 ', kleur.bgGreen().black(text));
break;
case 'notice':
console.log(' ', kleur.bgBlue().black(text));
break;
case 'error':
console.log('❌ ', kleur.bgRed().black(text));
break;
case 'warning':
console.log('⚠️ ', kleur.bgYellow().black(text));
break;
case 'waiting':
console.log('⏱ ', kleur.blue().italic(text));
if (timerID != null) {
console.timeLog(timerID);
timerID = null;
}
break;
default:
console.log(text);
break;
}
if (timerID != null) {
console.timeEnd(timerID);
}
console.log('');
}
export default message;
export {
message,
};

View File

@@ -0,0 +1,51 @@
/**
* @file Provides a decorator for cross-platform notification.
*/
import notifier from 'node-notifier';
/**
* Sends a cross-platform native notification.
*
* Wraps around node-notifier to assign default values.
*
* @param {string|object} options - The notification options or a message.
* @param {string} options.title - The notification title.
* @param {string} options.message - The notification message.
* @param {string} options.icon - The notification icon.
* @param {function} callback - The notification callback.
* @return {void}
*/
function notification(options, callback) {
if (typeof options === 'string') {
options = {
message: options
};
} else if (!options.title && !options.message) {
throw new TypeError(
'Notification expects at least a \'message\' parameter'
);
}
if (typeof options.icon === 'undefined') {
options.icon = 'https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png';
}
// If notification does not use a callback,
// shorten the wait before timing out.
if (typeof callback === 'undefined') {
if (typeof options.wait === 'undefined') {
if (typeof options.timeout === 'undefined') {
options.timeout = 5;
}
}
}
notifier.notify(options, callback);
}
export default notification;
export {
notification,
};

139
build/helpers/postcss.js Normal file
View File

@@ -0,0 +1,139 @@
/**
* @file If available, returns the PostCSS Processor creator and
* any the Autoprefixer PostCSS plugin.
*/
/**
* @typedef {import('autoprefixer').autoprefixer.Options} AutoprefixerOptions
*/
/**
* @typedef {import('postcss').AcceptedPlugin} AcceptedPlugin
*/
/**
* @typedef {import('postcss').Postcss} Postcss
*/
/**
* @typedef {import('postcss').ProcessOptions} ProcessOptions
*/
/**
* @typedef {import('postcss').Processor} Processor
*/
/**
* @typedef {AcceptedPlugin[]} PluginList
*/
/**
* @typedef {object<string, AcceptedPlugin>} PluginMap
*/
/**
* @typedef {PluginList|PluginMap} PluginCollection
*/
/**
* @typedef {object} PostCSSOptions
*
* @property {ProcessOptions} processor - The `Processor#process()` options.
* @property {AutoprefixerOptions} autoprefixer - The `autoprefixer()` options.
*/
/**
* @type {Postcss|undefined} postcss - The discovered PostCSS function.
* @type {AcceptedPlugin|undefined} autoprefixer - The discovered Autoprefixer function.
*/
let postcss, autoprefixer;
try {
postcss = await import('postcss');
postcss = postcss.default;
autoprefixer = await import('autoprefixer');
autoprefixer = autoprefixer.default;
} catch (err) {
// do nothing
}
/**
* @type {boolean} Whether PostCSS was discovered (TRUE) or not (FALSE).
*/
const supportsPostCSS = (typeof postcss === 'function');
/**
* @type {PluginList} A list of supported plugins.
*/
const pluginsList = [
autoprefixer,
];
/**
* @type {PluginMap} A map of supported plugins.
*/
const pluginsMap = {
'autoprefixer': autoprefixer,
};
/**
* Attempts to create a PostCSS Processor with the given plugins and options.
*
* @param {PluginCollection} pluginsListOrMap - A list or map of plugins.
* If a map of plugins, the plugin name looks up `options`.
* @param {PostCSSOptions} options - The PostCSS wrapper options.
*
* @returns {Processor|null}
*/
function createProcessor(pluginsListOrMap, options)
{
if (!postcss) {
return null;
}
const plugins = parsePlugins(pluginsListOrMap, options);
return postcss(plugins);
}
/**
* Parses the PostCSS plugins and options.
*
* @param {PluginCollection} pluginsListOrMap - A list or map of plugins.
* If a map of plugins, the plugin name looks up `options`.
* @param {PostCSSOptions} options - The PostCSS wrapper options.
*
* @returns {PluginList}
*/
function parsePlugins(pluginsListOrMap, options)
{
if (Array.isArray(pluginsListOrMap)) {
return pluginsListOrMap;
}
/** @type {PluginList} */
const plugins = [];
for (let [ name, plugin ] of Object.entries(pluginsListOrMap)) {
if (name in options) {
plugin = plugin[name](options[name]);
}
plugins.push(plugin);
}
return plugins;
}
export default postcss;
export {
autoprefixer,
createProcessor,
parsePlugins,
pluginsList,
pluginsMap,
postcss,
supportsPostCSS,
};

105
build/helpers/template.js Normal file
View File

@@ -0,0 +1,105 @@
/**
* @file Provides simple template tags.
*/
import loconfig from './config.js';
import {
escapeRegExp,
flatten
} from '../utils/index.js';
const templateData = flatten({
paths: loconfig.paths
});
/**
* Replaces all template tags from a map of keys and values.
*
* If replacement pairs contain a mix of substrings, regular expressions,
* and functions, regular expressions are executed last.
*
* @param {*} input - The value being searched and replaced on.
* If input is, or contains, a string, tags will be resolved.
* If input is, or contains, an object, it is mutated directly.
* If input is, or contains, an array, a shallow copy is returned.
* Otherwise, the value is left intact.
* @param {object} [data] - An object in the form `{ 'from': 'to', … }`.
* @return {*} Returns the transformed value.
*/
function resolve(input, data = templateData) {
switch (typeof input) {
case 'string': {
return resolveValue(input, data);
}
case 'object': {
if (input == null) {
break;
}
if (Array.isArray(input)) {
return input.map((value) => resolve(value, data));
} else {
for (const key in input) {
input[key] = resolve(input[key], data);
}
}
}
}
return input;
}
/**
* Replaces all template tags in a string from a map of keys and values.
*
* If replacement pairs contain a mix of substrings, regular expressions,
* and functions, regular expressions are executed last.
*
* @param {string} input - The string being searched and replaced on.
* @param {object} [data] - An object in the form `{ 'from': 'to', … }`.
* @return {string} Returns the translated string.
*/
function resolveValue(input, data = templateData) {
const tags = [];
if (data !== templateData) {
data = flatten(data);
}
for (let tag in data) {
tags.push(escapeRegExp(tag));
}
if (tags.length === 0) {
return input;
}
const search = new RegExp('\\{%\\s*(' + tags.join('|') + ')\\s*%\\}', 'g');
return input.replace(search, (match, key) => {
let value = data[key];
switch (typeof value) {
case 'function':
/**
* Retrieve the offset of the matched substring `args[0]`
* and the whole string being examined `args[1]`.
*/
let args = Array.prototype.slice.call(arguments, -2);
return value.call(data, match, args[0], args[1]);
case 'string':
case 'number':
return value;
}
return '';
});
}
export default resolve;
export {
resolve,
resolveValue,
};

View File

@@ -1,16 +0,0 @@
import browserSync from 'browser-sync';
import paths from '../mconfig.json';
export const server = browserSync.create();
function serve(done) {
server.init({
notify: false,
proxy: paths.url,
host: paths.url,
open: 'external'
});
done();
}
export default serve;

144
build/tasks/concats.js Normal file
View File

@@ -0,0 +1,144 @@
import loconfig from '../helpers/config.js';
import glob, { supportsGlob } from '../helpers/glob.js';
import message from '../helpers/message.js';
import notification from '../helpers/notification.js';
import resolve from '../helpers/template.js';
import { merge } from '../utils/index.js';
import concat from 'concat';
import {
basename,
normalize,
} from 'node:path';
/**
* @const {object} defaultGlobOptions - The default shared glob options.
* @const {object} developmentGlobOptions - The predefined glob options for development.
* @const {object} productionGlobOptions - The predefined glob options for production.
*/
export const defaultGlobOptions = {
};
export const developmentGlobOptions = Object.assign({}, defaultGlobOptions);
export const productionGlobOptions = Object.assign({}, defaultGlobOptions);
/**
* @typedef {object} ConcatOptions
* @property {boolean} removeDuplicates - Removes duplicate paths from
* the array of matching files and folders.
* Only the first occurrence of each path is kept.
*/
/**
* @const {ConcatOptions} defaultConcatOptions - The default shared concatenation options.
* @const {ConcatOptions} developmentConcatOptions - The predefined concatenation options for development.
* @const {ConcatOptions} productionConcatOptions - The predefined concatenation options for production.
*/
export const defaultConcatOptions = {
removeDuplicates: true,
};
export const developmentConcatOptions = Object.assign({}, defaultConcatOptions);
export const productionConcatOptions = Object.assign({}, defaultConcatOptions);
/**
* @const {object} developmentConcatFilesArgs - The predefined `concatFiles()` options for development.
* @const {object} productionConcatFilesArgs - The predefined `concatFiles()` options for production.
*/
export const developmentConcatFilesArgs = [
developmentGlobOptions,
developmentConcatOptions,
];
export const productionConcatFilesArgs = [
productionGlobOptions,
productionConcatOptions,
];
/**
* Concatenates groups of files.
*
* @todo Add support for minification.
*
* @async
* @param {object|boolean} [globOptions=null] - Customize the glob options.
* If `null`, default production options are used.
* If `false`, the glob function will be ignored.
* @param {object} [concatOptions=null] - Customize the concatenation options.
* If `null`, default production options are used.
* @return {Promise}
*/
export default async function concatFiles(globOptions = null, concatOptions = null) {
if (supportsGlob) {
if (globOptions == null) {
globOptions = productionGlobOptions;
} else if (
globOptions !== false &&
globOptions !== developmentGlobOptions &&
globOptions !== productionGlobOptions
) {
globOptions = merge({}, defaultGlobOptions, globOptions);
}
}
if (concatOptions == null) {
concatOptions = productionConcatOptions;
} else if (
concatOptions !== developmentConcatOptions &&
concatOptions !== productionConcatOptions
) {
concatOptions = merge({}, defaultConcatOptions, concatOptions);
}
/**
* @async
* @param {object} entry - The entrypoint to process.
* @param {string[]} entry.includes - One or more paths to process.
* @param {string} entry.outfile - The file to write to.
* @param {?string} [entry.label] - The task label.
* Defaults to the outfile name.
* @return {Promise}
*/
loconfig.tasks.concats?.forEach(async ({
includes,
outfile,
label = null
}) => {
if (!label) {
label = basename(outfile || 'undefined');
}
const timeLabel = `${label} concatenated in`;
console.time(timeLabel);
try {
if (!Array.isArray(includes)) {
includes = [ includes ];
}
includes = resolve(includes);
outfile = resolve(outfile);
if (supportsGlob && globOptions) {
includes = await glob(includes, globOptions);
}
if (concatOptions.removeDuplicates) {
includes = includes.map((path) => normalize(path));
includes = [ ...new Set(includes) ];
}
await concat(includes, outfile);
if (includes.length) {
message(`${label} concatenated`, 'success', timeLabel);
} else {
message(`${label} is empty`, 'notice', timeLabel);
}
} catch (err) {
message(`Error concatenating ${label}`, 'error');
message(err);
notification({
title: `${label} concatenation failed 🚨`,
message: `${err.name}: ${err.message}`
});
}
});
};

113
build/tasks/scripts.js Normal file
View File

@@ -0,0 +1,113 @@
import loconfig from '../helpers/config.js';
import message from '../helpers/message.js';
import notification from '../helpers/notification.js';
import resolve from '../helpers/template.js';
import { merge } from '../utils/index.js';
import esbuild from 'esbuild';
import { basename } from 'node:path';
/**
* @const {object} defaultESBuildOptions - The default shared ESBuild options.
* @const {object} developmentESBuildOptions - The predefined ESBuild options for development.
* @const {object} productionESBuildOptions - The predefined ESBuild options for production.
*/
export const defaultESBuildOptions = {
bundle: true,
color: true,
sourcemap: true,
target: [
'es2015',
],
};
export const developmentESBuildOptions = Object.assign({}, defaultESBuildOptions);
export const productionESBuildOptions = Object.assign({}, defaultESBuildOptions, {
logLevel: 'warning',
minify: true,
});
/**
* @const {object} developmentScriptsArgs - The predefined `compileScripts()` options for development.
* @const {object} productionScriptsArgs - The predefined `compileScripts()` options for production.
*/
export const developmentScriptsArgs = [
developmentESBuildOptions,
];
export const productionScriptsArgs = [
productionESBuildOptions,
];
/**
* Bundles and minifies main JavaScript files.
*
* @async
* @param {object} [esBuildOptions=null] - Customize the ESBuild build API options.
* If `null`, default production options are used.
* @return {Promise}
*/
export default async function compileScripts(esBuildOptions = null) {
if (esBuildOptions == null) {
esBuildOptions = productionESBuildOptions;
} else if (
esBuildOptions !== developmentESBuildOptions &&
esBuildOptions !== productionESBuildOptions
) {
esBuildOptions = merge({}, defaultESBuildOptions, esBuildOptions);
}
/**
* @async
* @param {object} entry - The entrypoint to process.
* @param {string[]} entry.includes - One or more paths to process.
* @param {string} [entry.outdir] - The directory to write to.
* @param {string} [entry.outfile] - The file to write to.
* @param {?string} [entry.label] - The task label.
* Defaults to the outdir or outfile name.
* @throws {TypeError} If outdir and outfile are missing.
* @return {Promise}
*/
loconfig.tasks.scripts?.forEach(async ({
includes,
outdir = '',
outfile = '',
label = null
}) => {
if (!label) {
label = basename(outdir || outfile || 'undefined');
}
const timeLabel = `${label} compiled in`;
console.time(timeLabel);
try {
if (!Array.isArray(includes)) {
includes = [ includes ];
}
includes = resolve(includes);
if (outdir) {
outdir = resolve(outdir);
} else if (outfile) {
outfile = resolve(outfile);
} else {
throw new TypeError(
'Expected \'outdir\' or \'outfile\''
);
}
await esbuild.build(Object.assign({}, esBuildOptions, {
entryPoints: includes,
outdir,
outfile,
}));
message(`${label} compiled`, 'success', timeLabel);
} catch (err) {
// errors managments (already done in esbuild)
notification({
title: `${label} compilation failed 🚨`,
message: `${err.errors[0].text} in ${err.errors[0].location.file} line ${err.errors[0].location.line}`
});
}
});
};

Some files were not shown because too many files have changed in this diff Show More