various tests
This commit is contained in:
parent
dfc55aafa9
commit
3bcf6f15af
15 changed files with 139 additions and 380 deletions
|
|
@ -7,6 +7,9 @@
|
|||
* - `src/config/transforms.js`
|
||||
*/
|
||||
|
||||
// get package.json
|
||||
const pkg = require('./package.json');
|
||||
|
||||
// module import filters
|
||||
const {
|
||||
wordCount,
|
||||
|
|
@ -109,6 +112,12 @@ module.exports = eleventyConfig => {
|
|||
|
||||
// --------------------- Passthrough File Copy -----------------------
|
||||
|
||||
// webc js and css dependencies
|
||||
eleventyConfig.addPassthroughCopy({
|
||||
'src/_includes/webc/*.css': `assets/components/`,
|
||||
'src/_includes/webc/*.js': `assets/components/`
|
||||
});
|
||||
|
||||
// node modules
|
||||
eleventyConfig.addPassthroughCopy({
|
||||
'node_modules/speedlify-score/speedlify-score.css': `assets/components/speedlify-score.css`,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@
|
|||
wcagLevel = 'WCAG2AAA'
|
||||
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cache"
|
||||
[plugins.inputs]
|
||||
paths = [ ".cache" ]
|
||||
|
||||
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
|
|
|
|||
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -27,6 +27,7 @@
|
|||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^5.1.7",
|
||||
"dayjs": "^1.11.5",
|
||||
"dotenv": "^16.0.3",
|
||||
"esbuild": "^0.15.10",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
|
|
@ -1628,6 +1629,15 @@
|
|||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
|
@ -8294,6 +8304,12 @@
|
|||
"domhandler": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "16.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
|
||||
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
|
||||
"dev": true
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"dev:postcss": "postcss src/assets/css/global.css --o dist/assets/css/global.css --watch --verbose",
|
||||
"dev:scripts": "esbuild src/assets/scripts/app.js src/assets/scripts/is-land.js --bundle --watch --outdir=dist/assets",
|
||||
"dev:scripts": "esbuild src/assets/scripts/app.js --bundle --watch --outdir=dist/assets",
|
||||
"dev:11ty": "eleventy --serve --watch",
|
||||
"build:postcss": "NODE_ENV=production postcss src/assets/css/global.css -o dist/assets/css/global.css",
|
||||
"build:11ty": "cross-env ELEVENTY_ENV=production eleventy",
|
||||
"build:scripts": "esbuild src/assets/scripts/app.js src/assets/scripts/is-land.js --bundle --minify --outdir=dist/assets --platform=node --tree-shaking=true",
|
||||
"build:scripts": "esbuild src/assets/scripts/app.js --bundle --minify --outdir=dist/assets --platform=node --tree-shaking=true",
|
||||
"start": "run-p dev:*",
|
||||
"build": "run-s clean build:*"
|
||||
},
|
||||
|
|
@ -43,6 +43,7 @@
|
|||
"cross-env": "^7.0.3",
|
||||
"cssnano": "^5.1.7",
|
||||
"dayjs": "^1.11.5",
|
||||
"dotenv": "^16.0.3",
|
||||
"esbuild": "^0.15.10",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
|
|
|
|||
14
src/_data/github.js
Normal file
14
src/_data/github.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
const EleventyFetch = require('@11ty/eleventy-fetch');
|
||||
|
||||
module.exports = async function () {
|
||||
let url = 'https://api.github.com/users/madrilene/repos';
|
||||
|
||||
// returning promise
|
||||
|
||||
let data = await EleventyFetch(url, {
|
||||
duration: '1d',
|
||||
type: 'json'
|
||||
});
|
||||
|
||||
return data;
|
||||
};
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
const package = require('../../package.json');
|
||||
|
||||
module.exports = {
|
||||
siteName: 'Lene Saile',
|
||||
siteDescription:
|
||||
|
|
@ -32,5 +34,6 @@ module.exports = {
|
|||
menu: {
|
||||
closedText: 'Menu'
|
||||
},
|
||||
env: process.env.ELEVENTY_ENV === 'production'
|
||||
env: process.env.ELEVENTY_ENV === 'production',
|
||||
pkv: package.version || 'v1'
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
{
|
||||
"text": "WebC",
|
||||
"url": "/test/"
|
||||
},
|
||||
{
|
||||
"text": "Github",
|
||||
"url": "/github/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
21
src/_includes/webc/my-marquee.webc
Normal file
21
src/_includes/webc/my-marquee.webc
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<marquee>Lorem ipsum dolor sit amet, consectetur</marquee>
|
||||
|
||||
<style webc:scoped>
|
||||
:host:defined {
|
||||
font-size: 3rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
customElements.define(
|
||||
'my-marquee',
|
||||
class extends HTMLElement {
|
||||
connectedCallback() {
|
||||
console.log(this);
|
||||
this.addEventListener('click', () => {
|
||||
console.log('clicked');
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
14
src/_includes/webc/speedlify-score.webc
Normal file
14
src/_includes/webc/speedlify-score.webc
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<speedlify-score
|
||||
webc:raw
|
||||
:class="this.class"
|
||||
:hash="this.hash"
|
||||
speedlify-url="https://www.speedlify.dev"
|
||||
:score="this.score"
|
||||
:weight="this.weight"
|
||||
:requests="this.requests"
|
||||
></speedlify-score>
|
||||
|
||||
<template>
|
||||
<link rel="stylesheet" :href="`/components/speedlify-score.css`" />
|
||||
<script :src="`/components/speedlify-score.js`"></script>
|
||||
</template>
|
||||
|
|
@ -1,31 +1,21 @@
|
|||
<is-land
|
||||
on:visible
|
||||
:import="`/web/dist/${this.pkg.version}/lite-yt-embed.js`"
|
||||
class="fluid-width-video-wrapper"
|
||||
<lite-youtube
|
||||
:videoid="this.slug"
|
||||
:params="this.start ? `start=${this.start}` : false"
|
||||
:playlabel="`Play${this.label ? `: ${this.label}` : ''}`"
|
||||
:style="`background-image:url('${this.poster || `https://i.ytimg.com/vi/${this.slug}/maxresdefault.jpg`}'); max-width: 100%`"
|
||||
>
|
||||
<lite-youtube
|
||||
:videoid="this.slug"
|
||||
:params="this.start ? `start=${this.start}` : false"
|
||||
:playlabel="`Play${this.label ? `: ${this.label}` : ''}`"
|
||||
:style="`background-image:url('${this.poster || `https://i.ytimg.com/vi/${this.slug}/maxresdefault.jpg`}'); max-width: 100%`"
|
||||
>
|
||||
<a
|
||||
:href="`https://youtube.com/watch?v=${this.slug}`"
|
||||
class="lty-playbtn"
|
||||
title="Play Video"
|
||||
><span
|
||||
class="lyt-visually-hidden"
|
||||
@html="`Play Video${this.label ? `: ${this.label}` : ''}`"
|
||||
></span
|
||||
></a>
|
||||
</lite-youtube>
|
||||
<template data-island>
|
||||
<style>
|
||||
/* Plugin bug: clicking the red youtube play icon in the center would navigate to youtube.com */
|
||||
lite-youtube:defined .lty-playbtn {
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" :href="`/web/dist/${this.pkg.version}/lite-yt-embed.css`" />
|
||||
</template>
|
||||
</is-land>
|
||||
<a
|
||||
:href="`https://youtube.com/watch?v=${this.slug}`"
|
||||
class="lty-playbtn"
|
||||
title="Play Video"
|
||||
><span
|
||||
class="lyt-visually-hidden"
|
||||
@html="`Play Video${this.label ? `: ${this.label}` : ''}`"
|
||||
></span
|
||||
></a>
|
||||
</lite-youtube>
|
||||
|
||||
<!-- <template>
|
||||
<link rel="stylesheet" :href="/assets/components/lite-yt-embed.css" />
|
||||
<script :src="/assets/components/lite-yt-embed.js"></script>
|
||||
</template> -->
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import {testGSAP} from './components/gsap';
|
||||
|
||||
// ------------------- cards redundant click, accessible whole card clickable solution by Heydon Pickering
|
||||
|
||||
const cards = [...document.querySelectorAll('.card')];
|
||||
|
|
@ -62,7 +60,3 @@ document.querySelectorAll('img').forEach(img => {
|
|||
}
|
||||
img.addEventListener('load', () => img.removeAttribute('data-is-loading'));
|
||||
});
|
||||
|
||||
// GSAP
|
||||
|
||||
// testGSAP();
|
||||
|
|
|
|||
|
|
@ -1,341 +0,0 @@
|
|||
const islandOnceCache = new Map();
|
||||
|
||||
class Island extends HTMLElement {
|
||||
static tagName = 'is-land';
|
||||
|
||||
static fallback = {
|
||||
':not(:defined)': (readyPromise, node, prefix) => {
|
||||
// remove from document to prevent web component init
|
||||
let cloned = document.createElement(prefix + node.localName);
|
||||
for (let attr of node.getAttributeNames()) {
|
||||
cloned.setAttribute(attr, node.getAttribute(attr));
|
||||
}
|
||||
|
||||
let children = Array.from(node.childNodes);
|
||||
for (let child of children) {
|
||||
cloned.append(child); // Keep the *same* child nodes, clicking on a details->summary child should keep the state of that child
|
||||
}
|
||||
node.replaceWith(cloned);
|
||||
|
||||
return readyPromise.then(() => {
|
||||
// restore children (not cloned)
|
||||
for (let child of Array.from(cloned.childNodes)) {
|
||||
node.append(child);
|
||||
}
|
||||
cloned.replaceWith(node);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static autoinit = {
|
||||
'petite-vue': function (library) {
|
||||
library.createApp().mount(this);
|
||||
},
|
||||
'vue': function (library) {
|
||||
library.createApp().mount(this);
|
||||
},
|
||||
'svelte': function (mod) {
|
||||
new mod.default({target: this});
|
||||
},
|
||||
'svelte-ssr': function (mod) {
|
||||
new mod.default({target: this, hydrate: true});
|
||||
},
|
||||
'preact': function (mod) {
|
||||
mod.default(this);
|
||||
}
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.attrs = {
|
||||
autoInitType: 'autoinit',
|
||||
import: 'import',
|
||||
template: 'data-island',
|
||||
ready: 'ready'
|
||||
};
|
||||
|
||||
this.conditionMap = {
|
||||
'visible': Conditions.visible,
|
||||
'idle': Conditions.idle,
|
||||
'interaction': Conditions.interaction,
|
||||
'media': Conditions.media,
|
||||
'save-data': Conditions.saveData
|
||||
};
|
||||
|
||||
// Internal promises
|
||||
this.ready = new Promise((resolve, reject) => {
|
||||
this.readyResolve = resolve;
|
||||
this.readyReject = reject;
|
||||
});
|
||||
}
|
||||
|
||||
static getParents(el, selector, stopAt = false) {
|
||||
let nodes = [];
|
||||
while (el) {
|
||||
if (el.matches && el.matches(selector)) {
|
||||
if (stopAt && el === stopAt) {
|
||||
break;
|
||||
}
|
||||
|
||||
nodes.push(el);
|
||||
}
|
||||
el = el.parentNode;
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
static async ready(el) {
|
||||
let parents = Island.getParents(el, Island.tagName);
|
||||
let imports = await Promise.all(parents.map(el => el.wait()));
|
||||
|
||||
// return innermost module import
|
||||
if (imports.length) {
|
||||
return imports[0];
|
||||
}
|
||||
}
|
||||
|
||||
async forceFallback() {
|
||||
let prefix = Island.tagName + '--';
|
||||
let promises = [];
|
||||
|
||||
if (window.Island) {
|
||||
Object.assign(Island.fallback, window.Island.fallback);
|
||||
}
|
||||
|
||||
for (let selector in Island.fallback) {
|
||||
// Reverse here as a cheap way to get the deepest nodes first
|
||||
let components = Array.from(this.querySelectorAll(selector)).reverse();
|
||||
|
||||
// with thanks to https://gist.github.com/cowboy/938767
|
||||
for (let node of components) {
|
||||
if (!node.isConnected || node.localName === Island.tagName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let readyPromise = Island.ready(node);
|
||||
promises.push(Island.fallback[selector](readyPromise, node, prefix));
|
||||
}
|
||||
}
|
||||
|
||||
return promises;
|
||||
}
|
||||
|
||||
wait() {
|
||||
return this.ready;
|
||||
}
|
||||
|
||||
getConditions() {
|
||||
let map = {};
|
||||
for (let key of Object.keys(this.conditionMap)) {
|
||||
if (this.hasAttribute(`on:${key}`)) {
|
||||
map[key] = this.getAttribute(`on:${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
// Keep fallback content without initializing the components
|
||||
// TODO improvement: only run this for not-eager components?
|
||||
await this.forceFallback();
|
||||
|
||||
await this.hydrate();
|
||||
}
|
||||
|
||||
getTemplates() {
|
||||
return this.querySelectorAll(`:scope template[${this.attrs.template}]`);
|
||||
}
|
||||
|
||||
replaceTemplates(templates) {
|
||||
// replace <template> with the live content
|
||||
for (let node of templates) {
|
||||
if (Island.getParents(node, Island.tagName, this).length > 0) {
|
||||
continue;
|
||||
}
|
||||
let value = node.getAttribute(this.attrs.template);
|
||||
// get rid of the rest of the content on the island
|
||||
if (value === 'replace') {
|
||||
let children = Array.from(this.childNodes);
|
||||
for (let child of children) {
|
||||
this.removeChild(child);
|
||||
}
|
||||
this.appendChild(node.content);
|
||||
break;
|
||||
} else {
|
||||
if (value === 'once' && node.innerHTML) {
|
||||
if (islandOnceCache.has(node.innerHTML)) {
|
||||
node.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
islandOnceCache.set(node.innerHTML, true);
|
||||
}
|
||||
|
||||
node.replaceWith(node.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async hydrate() {
|
||||
let conditions = [];
|
||||
if (this.parentNode) {
|
||||
// wait for all parents before hydrating
|
||||
conditions.push(Island.ready(this.parentNode));
|
||||
}
|
||||
|
||||
let attrs = this.getConditions();
|
||||
for (let condition in attrs) {
|
||||
if (this.conditionMap[condition]) {
|
||||
conditions.push(this.conditionMap[condition](attrs[condition], this));
|
||||
}
|
||||
}
|
||||
|
||||
// Loading conditions must finish before dependencies are loaded
|
||||
await Promise.all(conditions);
|
||||
|
||||
this.replaceTemplates(this.getTemplates());
|
||||
|
||||
let mod;
|
||||
// [dependency="my-component-code.js"]
|
||||
let importScript = this.getAttribute(this.attrs.import);
|
||||
if (importScript) {
|
||||
// we could resolve import maps here manually but you’d still have to use the full URL in your script’s import anyway
|
||||
mod = await import(importScript);
|
||||
}
|
||||
|
||||
if (mod) {
|
||||
// Use `import=""` for when import maps are available e.g. `import="petite-vue"`
|
||||
let fn =
|
||||
Island.autoinit[this.getAttribute(this.attrs.autoInitType) || importScript];
|
||||
|
||||
if (fn) {
|
||||
await fn.call(this, mod);
|
||||
}
|
||||
}
|
||||
|
||||
this.readyResolve({
|
||||
import: mod
|
||||
});
|
||||
|
||||
this.setAttribute(this.attrs.ready, '');
|
||||
}
|
||||
}
|
||||
|
||||
class Conditions {
|
||||
static visible(noop, el) {
|
||||
if (!('IntersectionObserver' in window)) {
|
||||
// runs immediately
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = new IntersectionObserver(entries => {
|
||||
let [entry] = entries;
|
||||
if (entry.isIntersecting) {
|
||||
observer.unobserve(entry.target);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO make sure this runs after all of the conditions have finished, otherwise it will
|
||||
// finish way before the other lazy loaded promises and will be the same as a noop when
|
||||
// on:interaction or on:visible finishes much later
|
||||
static idle() {
|
||||
let onload = new Promise(resolve => {
|
||||
if (document.readyState !== 'complete') {
|
||||
window.addEventListener('load', () => resolve(), {once: true});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
if (!('requestIdleCallback' in window)) {
|
||||
// run immediately
|
||||
return onload;
|
||||
}
|
||||
|
||||
// both idle and onload
|
||||
return Promise.all([
|
||||
new Promise(resolve => {
|
||||
requestIdleCallback(() => {
|
||||
resolve();
|
||||
});
|
||||
}),
|
||||
onload
|
||||
]);
|
||||
}
|
||||
|
||||
static interaction(eventOverrides, el) {
|
||||
let events = ['click', 'touchstart'];
|
||||
// event overrides e.g. on:interaction="mouseenter"
|
||||
if (eventOverrides) {
|
||||
events = (eventOverrides || '').split(',').map(entry => entry.trim());
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
function resolveFn(e) {
|
||||
resolve();
|
||||
|
||||
// cleanup the other event handlers
|
||||
for (let name of events) {
|
||||
el.removeEventListener(name, resolveFn);
|
||||
}
|
||||
}
|
||||
|
||||
for (let name of events) {
|
||||
el.addEventListener(name, resolveFn, {once: true});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static media(query) {
|
||||
let mm = {
|
||||
matches: true
|
||||
};
|
||||
|
||||
if (query && 'matchMedia' in window) {
|
||||
mm = window.matchMedia(query);
|
||||
}
|
||||
|
||||
if (mm.matches) {
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
mm.addListener(e => {
|
||||
if (e.matches) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static saveData(expects) {
|
||||
// return early if API does not exist
|
||||
if (
|
||||
!('connection' in navigator) ||
|
||||
navigator.connection.saveData === (expects !== 'false')
|
||||
) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// dangly promise
|
||||
return new Promise(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
// Should this auto define? Folks can redefine later using { component } export
|
||||
if ('customElements' in window) {
|
||||
window.customElements.define(Island.tagName, Island);
|
||||
window.Island = Island;
|
||||
}
|
||||
|
||||
export const component = Island;
|
||||
|
||||
export const ready = Island.ready;
|
||||
16
src/pages/github.njk
Normal file
16
src/pages/github.njk
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
title: Github
|
||||
permalink: /github/index.html
|
||||
description: This is just a testing environment
|
||||
layout: page
|
||||
---
|
||||
|
||||
<ul>
|
||||
{% for repository in github %}
|
||||
<li>
|
||||
<a href="{{ repository.html_url }}">{{ repository.name }} </a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li>This would display if the 'item' collection were empty</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
|
@ -5,11 +5,23 @@ description: This is just a testing environment
|
|||
layout: page
|
||||
---
|
||||
|
||||
Version number {{ meta.pkv }}
|
||||
|
||||
<!-- sdfg -->
|
||||
|
||||
{% renderTemplate "webc" %}
|
||||
<my-marquee>dsfgdfg</my-marquee>
|
||||
{% endrenderTemplate %}
|
||||
|
||||
<p>
|
||||
Icing jelly soufflé shortbread chocolate cake muffin gummies cotton candy lemon drops.
|
||||
Cake gummi bears dragée chocolate sweet croissant sweet croissant.
|
||||
</p>
|
||||
|
||||
{% renderTemplate "webc" %}
|
||||
<youtube-lite-player @slug="DC5fP_8Q8uQ" @label="{{ title }}"></youtube-lite-player>
|
||||
{% endrenderTemplate %}
|
||||
|
||||
<h2>Testing counter</h2>
|
||||
|
||||
<p>counter inside island, activate on interaction</p>
|
||||
|
|
|
|||
Loading…
Reference in a new issue