Compare commits
20 Commits
v1.0.0-RC.
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd72e9fbbe | ||
| eeb73fb393 | |||
| 1b137868fb | |||
| 05deb182e8 | |||
| c076620755 | |||
| 388790bbae | |||
| 7de12ffe92 | |||
|
|
7dcbf060c8 | ||
| c8e8bc5d80 | |||
| 05d72f6d03 | |||
| f008ea821f | |||
| 590340e4da | |||
| 8144c99ceb | |||
| 4e0082b3f3 | |||
| 2248cf1c8d | |||
| 1d819d6ea6 | |||
| a09b549219 | |||
| b321fb4698 | |||
| 01c639ceca | |||
| 2598314c2b |
@@ -1,7 +1,16 @@
|
|||||||
{
|
{
|
||||||
"extends": "airbnb-base",
|
"plugins": [
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"airbnb-base",
|
||||||
|
"prettier"
|
||||||
|
],
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"jest": true
|
"jest": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"prettier/prettier": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "all"
|
||||||
|
}
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
{
|
{
|
||||||
"extends": [ "stylelint-config-standard" ],
|
"plugins": [
|
||||||
|
"stylelint-prettier"
|
||||||
|
],
|
||||||
|
"extends": [
|
||||||
|
"stylelint-config-standard",
|
||||||
|
"stylelint-prettier/recommended"
|
||||||
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"prettier/prettier": true,
|
||||||
"selector-pseudo-element-colon-notation": "single"
|
"selector-pseudo-element-colon-notation": "single"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const { writeFile } = require('fs');
|
const { writeFile } = require("fs");
|
||||||
const { resolve } = require('path');
|
const { resolve } = require("path");
|
||||||
const imagemin = require('imagemin');
|
const imagemin = require("imagemin");
|
||||||
const imageminPngquant = require('imagemin-pngquant');
|
const imageminPngquant = require("imagemin-pngquant");
|
||||||
const imageminGifsicle = require('imagemin-gifsicle');
|
const imageminGifsicle = require("imagemin-gifsicle");
|
||||||
const imageminJpegtran = require('imagemin-jpegtran');
|
const imageminJpegtran = require("imagemin-jpegtran");
|
||||||
|
|
||||||
imagemin(['images/*.{png,jpg,gif}'], 'theme/images', {
|
imagemin(["images/*.{png,jpg,gif}"], "theme/images", {
|
||||||
plugins: [
|
plugins: [
|
||||||
imageminPngquant({
|
imageminPngquant({
|
||||||
quality: [0.65, 0.8],
|
quality: [0.65, 0.8],
|
||||||
@@ -15,18 +15,20 @@ imagemin(['images/*.{png,jpg,gif}'], 'theme/images', {
|
|||||||
}),
|
}),
|
||||||
imageminJpegtran(),
|
imageminJpegtran(),
|
||||||
],
|
],
|
||||||
}).then((files) => {
|
})
|
||||||
files.forEach((file) => {
|
.then(files => {
|
||||||
const path = resolve(__dirname, '../', file.path);
|
files.forEach(file => {
|
||||||
writeFile(path, file.data, (error) => {
|
const path = resolve(__dirname, "../", file.path);
|
||||||
|
writeFile(path, file.data, error => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error);
|
process.stdout.write(`${error}\n`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
console.log(`File written: ${path}`);
|
process.stdout.write(`File written: ${path}\n`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).catch((error) => {
|
})
|
||||||
console.error(error);
|
.catch(error => {
|
||||||
|
process.stderr.write(`${error}\n`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
const { resolve } = require('path');
|
const { resolve } = require("path");
|
||||||
const { execSync } = require('child_process');
|
const { execSync } = require("child_process");
|
||||||
const { exec, upAll, stop } = require('docker-compose');
|
const { upAll, stop } = require("docker-compose");
|
||||||
const browsersync = require('browser-sync');
|
const browsersync = require("browser-sync");
|
||||||
const mysql = require('mysql');
|
const mysql = require("mysql");
|
||||||
|
|
||||||
const name = 'windycoys';
|
const name = "windycoys";
|
||||||
|
|
||||||
const dockerOptions = {
|
const dockerOptions = {
|
||||||
cwd: resolve(__dirname),
|
cwd: resolve(__dirname),
|
||||||
@@ -12,24 +12,26 @@ const dockerOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const browserSyncOptions = {
|
const browserSyncOptions = {
|
||||||
files: [
|
files: ["theme/**/*"],
|
||||||
'theme/**/*',
|
|
||||||
],
|
|
||||||
watchtask: true,
|
watchtask: true,
|
||||||
open: false,
|
open: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mysqlConfig = {
|
const mysqlConfig = {
|
||||||
user: 'root',
|
user: "root",
|
||||||
password: 'password',
|
password: "password",
|
||||||
database: 'wordpress',
|
database: "wordpress",
|
||||||
};
|
};
|
||||||
|
|
||||||
process.env.COMPOSE_PROJECT_NAME = name;
|
process.env.COMPOSE_PROJECT_NAME = name;
|
||||||
|
|
||||||
// Get IP address
|
// Get IP address
|
||||||
const getIpAddr = function getIpAddr(id) {
|
const getIpAddr = function getIpAddr(id) {
|
||||||
return execSync(`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${id}`).toString('utf8').trim();
|
return execSync(
|
||||||
|
`docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${id}`,
|
||||||
|
)
|
||||||
|
.toString("utf8")
|
||||||
|
.trim();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update URIs in MYSQL database
|
// Update URIs in MYSQL database
|
||||||
@@ -40,9 +42,9 @@ const updateUriData = function updateUriData(wordpress, db) {
|
|||||||
|
|
||||||
const query = `UPDATE wp_options SET option_value='http://${wordpress}' WHERE option_name in ('siteurl', 'home')`;
|
const query = `UPDATE wp_options SET option_value='http://${wordpress}' WHERE option_name in ('siteurl', 'home')`;
|
||||||
|
|
||||||
con.query(query, (error) => {
|
con.query(query, error => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Error', error.sqlMessage);
|
process.stderr.write(`Error: ${error.sqlMessage}\n`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -54,26 +56,28 @@ const updateUriData = function updateUriData(wordpress, db) {
|
|||||||
const exitHandler = function exitHandler() {
|
const exitHandler = function exitHandler() {
|
||||||
stop(dockerOptions).then(
|
stop(dockerOptions).then(
|
||||||
() => {
|
() => {
|
||||||
console.log('\n');
|
process.stdout.write("\n");
|
||||||
process.exit();
|
process.exit();
|
||||||
},
|
},
|
||||||
(err) => {
|
err => {
|
||||||
console.error('Error:', err.message);
|
process.stderr.write(`Error: ${err.message}\n`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
process.on('beforeExit', exitHandler.bind());
|
process.on("beforeExit", exitHandler.bind());
|
||||||
process.on('SIGINT', exitHandler.bind());
|
process.on("SIGINT", exitHandler.bind());
|
||||||
process.on('SIGUSR1', exitHandler.bind());
|
process.on("SIGUSR1", exitHandler.bind());
|
||||||
process.on('SIGUSR2', exitHandler.bind());
|
process.on("SIGUSR2", exitHandler.bind());
|
||||||
process.on('uncaughtException', exitHandler.bind());
|
process.on("uncaughtException", exitHandler.bind());
|
||||||
|
|
||||||
// Start Docker containers
|
// Start Docker containers
|
||||||
upAll(dockerOptions).then(
|
upAll(dockerOptions).then(
|
||||||
() => {
|
() => {
|
||||||
console.log('Docker containers launched, starting browser-sync...');
|
process.stdout.write(
|
||||||
|
"Docker containers launched, starting browser-sync...",
|
||||||
|
);
|
||||||
const wordpress = getIpAddr(`${name}_wordpress_1`);
|
const wordpress = getIpAddr(`${name}_wordpress_1`);
|
||||||
const db = getIpAddr(`${name}_db_1`);
|
const db = getIpAddr(`${name}_db_1`);
|
||||||
if (wordpress && db) {
|
if (wordpress && db) {
|
||||||
@@ -82,12 +86,14 @@ upAll(dockerOptions).then(
|
|||||||
browserSyncOptions.proxy = wordpress;
|
browserSyncOptions.proxy = wordpress;
|
||||||
bs.init(browserSyncOptions);
|
bs.init(browserSyncOptions);
|
||||||
} else {
|
} else {
|
||||||
console.error('Error', 'No IP address for Docker containers. Aborting.');
|
process.stderr.write(
|
||||||
|
"Error: No IP address for Docker containers. Aborting.\n",
|
||||||
|
);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err) => {
|
err => {
|
||||||
console.error('Error', err.message);
|
process.stderr.write(`Error: ${err.message}\n`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.comments__list--sub-list .comments__item {
|
.comments__list--sub-list .comments__item {
|
||||||
border-left: 2px solid var(--color-light-grey);
|
border-left: 2px solid var(--color-light-blue);
|
||||||
padding-left: var(--space-sm);
|
padding-left: var(--space-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,36 +39,49 @@
|
|||||||
|
|
||||||
.content ul,
|
.content ul,
|
||||||
.content ol {
|
.content ol {
|
||||||
|
counter-reset: li;
|
||||||
margin-bottom: var(--space-sm);
|
margin-bottom: var(--space-sm);
|
||||||
padding-left: var(--space-sm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content ul li,
|
.content ul li,
|
||||||
.content ol li {
|
.content ol li {
|
||||||
|
counter-increment: li;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 0 var(--space-xs) var(--space-sm);
|
margin-bottom: var(--space-xs);
|
||||||
|
padding-left: var(--space-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content ul li:before,
|
||||||
|
.content ol li:before {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content ul li:before {
|
.content ul li:before {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
|
||||||
left: calc(var(--space-xxs) - (var(--bullet-size) / 2));
|
|
||||||
top: calc(var(--base-line-height) / 2 * 1rem);
|
top: calc(var(--base-line-height) / 2 * 1rem);
|
||||||
background-color: var(--color-dark-blue);
|
background-color: var(--color-light-blue);
|
||||||
width: var(--bullet-size);
|
width: var(--bullet-size);
|
||||||
height: var(--bullet-size);
|
height: var(--bullet-size);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content ol li:before {
|
||||||
|
content: counter(li) ".";
|
||||||
|
top: 0;
|
||||||
|
color: var(--color-light-blue);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
.content a {
|
.content a {
|
||||||
color: var(--color-light-blue);
|
color: var(--color-light-blue);
|
||||||
transition: box-shadow var(--transition-md) ease-out;
|
transition: box-shadow var(--transition-md) ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content a img {
|
.content a img {
|
||||||
transition:
|
transition: box-shadow var(--transition-md) ease-out,
|
||||||
box-shadow var(--transition-md) ease-out,
|
|
||||||
filter var(--transition-md) ease-out;
|
filter var(--transition-md) ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +137,16 @@
|
|||||||
margin: var(--space-sm) 0 0;
|
margin: var(--space-sm) 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content .wp-block-quote {
|
||||||
|
border-left: var(--space-xxs) solid var(--color-light-blue);
|
||||||
|
margin-bottom: var(--space-sm);
|
||||||
|
padding: var(--space-sm) var(--space-md);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content .wp-block-quote cite {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
.content table {
|
.content table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
|
|||||||
@@ -64,11 +64,11 @@
|
|||||||
--transition-fs: 0.15s;
|
--transition-fs: 0.15s;
|
||||||
--transition-md: 0.3s;
|
--transition-md: 0.3s;
|
||||||
--transition-sl: 0.6s;
|
--transition-sl: 0.6s;
|
||||||
--heading-font-family: 'Raleway', sans-serif;
|
--heading-font-family: "Raleway", sans-serif;
|
||||||
--body-font-family: 'Open Sans', sans-serif;
|
--body-font-family: "Open Sans", sans-serif;
|
||||||
--link-focus: 0 0.1rem 0 0 var(--color-light-blue);
|
--link-focus: 0 0.1rem 0 0 var(--color-light-blue);
|
||||||
--image-focus: 0 0 0 0.2rem #fff, 0 0 0 0.4rem var(--color-light-blue);
|
--image-focus: 0 0 0 0.2rem #fff, 0 0 0 0.4rem var(--color-light-blue);
|
||||||
--bullet-size: 0.334rem;
|
--bullet-size: 0.45rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@custom-media --viewport-sm (min-width: 30rem);
|
@custom-media --viewport-sm (min-width: 30rem);
|
||||||
|
|||||||
@@ -9,8 +9,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
top: var(--space-xxs);
|
top: var(--space-xxs);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition:
|
transition: filter var(--transition-md) ease-out,
|
||||||
filter var(--transition-md) ease-out,
|
|
||||||
opacity var(--transition-md) ease-out,
|
opacity var(--transition-md) ease-out,
|
||||||
transform var(--transition-md) ease-out;
|
transform var(--transition-md) ease-out;
|
||||||
width: var(--menu-size);
|
width: var(--menu-size);
|
||||||
|
|||||||
@@ -79,8 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.metadata__tag-link {
|
.metadata__tag-link {
|
||||||
transition:
|
transition: box-shadow var(--transition-md) ease-out,
|
||||||
box-shadow var(--transition-md) ease-out,
|
|
||||||
color var(--transition-md) ease-out;
|
color var(--transition-md) ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
css/nav.css
17
css/nav.css
@@ -5,13 +5,12 @@
|
|||||||
.nav:after {
|
.nav:after {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
content: '';
|
content: "";
|
||||||
left: 0;
|
left: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
transition:
|
transition: opacity var(--nav-transition-duration) ease-out,
|
||||||
opacity var(--nav-transition-duration) ease-out,
|
|
||||||
visibility var(--nav-transition-duration) ease-out;
|
visibility var(--nav-transition-duration) ease-out;
|
||||||
top: 0;
|
top: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
@@ -90,8 +89,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: var(--space-sm);
|
right: var(--space-sm);
|
||||||
top: var(--space-sm);
|
top: var(--space-sm);
|
||||||
transition:
|
transition: box-shadow var(--nav-transition-duration) ease-out,
|
||||||
box-shadow var(--nav-transition-duration) ease-out,
|
|
||||||
filter var(--nav-transition-duration) ease-out;
|
filter var(--nav-transition-duration) ease-out;
|
||||||
width: var(--icon-size-sm);
|
width: var(--icon-size-sm);
|
||||||
}
|
}
|
||||||
@@ -111,7 +109,8 @@
|
|||||||
height: 8%;
|
height: 8%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
transition: transform var(--nav-transition-duration) ease-out var(--nav-transition-duration);
|
transition: transform var(--nav-transition-duration) ease-out
|
||||||
|
var(--nav-transition-duration);
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
top: 50%;
|
top: 50%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -143,8 +142,7 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-bottom: var(--space-xs);
|
margin-bottom: var(--space-xs);
|
||||||
transition:
|
transition: box-shadow var(--nav-transition-duration) ease-out,
|
||||||
box-shadow var(--nav-transition-duration) ease-out,
|
|
||||||
text-shadow var(--nav-transition-duration) ease-out;
|
text-shadow var(--nav-transition-duration) ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,8 +169,7 @@
|
|||||||
.nav__social-link:visited {
|
.nav__social-link:visited {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
transition:
|
transition: box-shadow var(--nav-transition-duration) ease-out,
|
||||||
box-shadow var(--nav-transition-duration) ease-out,
|
|
||||||
filter var(--nav-transition-duration) ease-out;
|
filter var(--nav-transition-duration) ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
css/page.css
10
css/page.css
@@ -72,7 +72,9 @@
|
|||||||
@media (--viewport-lg) {
|
@media (--viewport-lg) {
|
||||||
.page {
|
.page {
|
||||||
grid-template-columns: var(--logo-size-lg) 1fr;
|
grid-template-columns: var(--logo-size-lg) 1fr;
|
||||||
grid-template-rows: var(--icon-size-md) calc(var(--logo-size-lg) - var(--space-md) - 32px) 1fr;
|
grid-template-rows:
|
||||||
|
var(--icon-size-md) calc(var(--logo-size-lg) - var(--space-md) - 32px)
|
||||||
|
1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page__logo {
|
.page__logo {
|
||||||
@@ -93,7 +95,11 @@
|
|||||||
@media (--viewport-xl) {
|
@media (--viewport-xl) {
|
||||||
.page {
|
.page {
|
||||||
grid-template-columns: var(--logo-size-xl) 1fr;
|
grid-template-columns: var(--logo-size-xl) 1fr;
|
||||||
grid-template-rows: var(--icon-size-md) calc(var(--logo-size-xl) - var(--space-md) - var(--icon-size-md)) 1fr;
|
grid-template-rows:
|
||||||
|
var(--icon-size-md) calc(
|
||||||
|
var(--logo-size-xl) - var(--space-md) - var(--icon-size-md)
|
||||||
|
)
|
||||||
|
1fr;
|
||||||
margin: var(--space-md) auto 0;
|
margin: var(--space-md) auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
.social {
|
.social {
|
||||||
text-align: right;
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social__item {
|
||||||
|
margin-left: var(--space-xs);
|
||||||
}
|
}
|
||||||
|
|
||||||
.social__link {
|
.social__link {
|
||||||
display: inline-block;
|
display: block;
|
||||||
transition:
|
background-color: transparent;
|
||||||
filter var(--transition-fs) ease-out,
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
transition: filter var(--transition-fs) ease-out,
|
||||||
transform var(--transition-fs) ease-out;
|
transform var(--transition-fs) ease-out;
|
||||||
transform-origin: center bottom;
|
transform-origin: center bottom;
|
||||||
}
|
}
|
||||||
@@ -15,3 +23,17 @@
|
|||||||
filter: saturate(1.5) contrast(1.5);
|
filter: saturate(1.5) contrast(1.5);
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Donate button */
|
||||||
|
|
||||||
|
.social__item input[type="image"] {
|
||||||
|
transition: filter var(--transition-fs) ease-out,
|
||||||
|
transform var(--transition-fs) ease-out;
|
||||||
|
transform-origin: center bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.social__item input[type="image"]:focus,
|
||||||
|
.social__item input[type="image"]:hover {
|
||||||
|
filter: saturate(1.5) contrast(1.5);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export default class Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
if (this.dataset.loadTransition === 'false') {
|
if (this.dataset.loadTransition === "false") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.image.style.opacity = 0;
|
this.image.style.opacity = 0;
|
||||||
@@ -21,6 +21,6 @@ export default class Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
attachLoadedEvent() {
|
attachLoadedEvent() {
|
||||||
this.image.addEventListener('load', () => this.fadeIn());
|
this.image.addEventListener("load", () => this.fadeIn());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +1,46 @@
|
|||||||
import Image from './image';
|
import Image from "./image";
|
||||||
|
|
||||||
const imageHtml = `
|
const imageHtml = `
|
||||||
<img class="image" src="foo.jpg"></img>
|
<img class="image" src="foo.jpg"></img>
|
||||||
<img class="disabled-image" data-load-transition="false" src="foo.jpg"></img>
|
<img class="disabled-image" data-load-transition="false" src="foo.jpg"></img>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
describe('Image', () => {
|
describe("Image", () => {
|
||||||
let image;
|
let image;
|
||||||
let disabledImage;
|
let disabledImage;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = imageHtml;
|
document.body.innerHTML = imageHtml;
|
||||||
image = document.querySelector('.image');
|
image = document.querySelector(".image");
|
||||||
disabledImage = document.querySelector('.disabled-image');
|
disabledImage = document.querySelector(".disabled-image");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should initialize', () => {
|
it("Should initialize", () => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
expect(img).toBeInstanceOf(Image);
|
expect(img).toBeInstanceOf(Image);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should store a reference to the image element', () => {
|
it("Should store a reference to the image element", () => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
expect(img.image).toBe(image);
|
expect(img.image).toBe(image);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('fadeIn should set the element opacity to 1', () => {
|
test("fadeIn should set the element opacity to 1", () => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
img.fadeIn();
|
img.fadeIn();
|
||||||
expect(img.image.style.opacity).toBe('1');
|
expect(img.image.style.opacity).toBe("1");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('start should set the element opacity to 0', () => {
|
test("start should set the element opacity to 0", () => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
img.start();
|
img.start();
|
||||||
expect(img.image.style.opacity).toBe('0');
|
expect(img.image.style.opacity).toBe("0");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('start should call fadeIn when image has already loaded', () => {
|
test("start should call fadeIn when image has already loaded", () => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
img.fadeIn = jest.fn();
|
img.fadeIn = jest.fn();
|
||||||
Object.defineProperty(img.image, 'complete', {
|
Object.defineProperty(img.image, "complete", {
|
||||||
value: true,
|
value: true,
|
||||||
writable: false,
|
writable: false,
|
||||||
});
|
});
|
||||||
@@ -48,10 +48,10 @@ describe('Image', () => {
|
|||||||
expect(img.fadeIn).toHaveBeenCalledTimes(1);
|
expect(img.fadeIn).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('start should call attachLoadedEvent if image has not yet loaded', () => {
|
test("start should call attachLoadedEvent if image has not yet loaded", () => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
img.attachLoadedEvent = jest.fn();
|
img.attachLoadedEvent = jest.fn();
|
||||||
Object.defineProperty(img.image, 'complete', {
|
Object.defineProperty(img.image, "complete", {
|
||||||
value: false,
|
value: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
});
|
});
|
||||||
@@ -59,7 +59,7 @@ describe('Image', () => {
|
|||||||
expect(img.attachLoadedEvent).toHaveBeenCalledTimes(1);
|
expect(img.attachLoadedEvent).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('start should do nothing if data-load-transition=false', () => {
|
test("start should do nothing if data-load-transition=false", () => {
|
||||||
const img = new Image(disabledImage);
|
const img = new Image(disabledImage);
|
||||||
img.attachLoadedEvent = jest.fn();
|
img.attachLoadedEvent = jest.fn();
|
||||||
img.start();
|
img.start();
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
import windy from './windy';
|
import windy from "./windy";
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', windy);
|
document.addEventListener("DOMContentLoaded", windy);
|
||||||
|
|||||||
29
js/menu.js
29
js/menu.js
@@ -1,20 +1,20 @@
|
|||||||
const STATES = {
|
const STATES = {
|
||||||
visible: 'is-visible',
|
visible: "is-visible",
|
||||||
minimized: 'is-minimized',
|
minimized: "is-minimized",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Menu {
|
export default class Menu {
|
||||||
constructor(cfg = {}) {
|
constructor(cfg = {}) {
|
||||||
if (!cfg.container) return false;
|
if (!cfg.container) return false;
|
||||||
this.container = cfg.container;
|
this.container = cfg.container;
|
||||||
this.state = 'visible';
|
this.state = "visible";
|
||||||
this.lastKnownScrollPosition = 0;
|
this.lastKnownScrollPosition = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (!this.state) return false;
|
if (!this.state) return false;
|
||||||
this.container.setAttribute('aria-haspopup', true);
|
this.container.setAttribute("aria-haspopup", true);
|
||||||
this.container.setAttribute('aria-expanded', false);
|
this.container.setAttribute("aria-expanded", false);
|
||||||
this.attachEvents();
|
this.attachEvents();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.showMenu();
|
this.showMenu();
|
||||||
@@ -23,38 +23,37 @@ export default class Menu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
attachEvents() {
|
attachEvents() {
|
||||||
window.addEventListener('scroll', () => {
|
window.addEventListener("scroll", () => {
|
||||||
this.updateState(this.lastKnownScrollPosition, window.scrollY);
|
this.updateState(this.lastKnownScrollPosition, window.scrollY);
|
||||||
this.lastKnownScrollPosition = window.scrollY;
|
this.lastKnownScrollPosition = window.scrollY;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateState(lastY = 0, currentY) {
|
updateState(lastY = 0, currentY) {
|
||||||
if (this.state !== 'hidden') {
|
if (this.state !== "hidden") {
|
||||||
if (this.state !== 'visible' && currentY < lastY) {
|
if (this.state !== "visible" && currentY < lastY) {
|
||||||
this.showMenu();
|
this.showMenu();
|
||||||
} else if (this.state !== 'minimized' && currentY
|
} else if (this.state !== "minimized" && currentY > lastY) {
|
||||||
> lastY) {
|
|
||||||
this.minimizeMenu();
|
this.minimizeMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showMenu() {
|
showMenu() {
|
||||||
this.state = 'visible';
|
this.state = "visible";
|
||||||
this.container.setAttribute('aria-expanded', false);
|
this.container.setAttribute("aria-expanded", false);
|
||||||
this.container.classList.add(STATES.visible);
|
this.container.classList.add(STATES.visible);
|
||||||
this.container.classList.remove(STATES.minimized);
|
this.container.classList.remove(STATES.minimized);
|
||||||
}
|
}
|
||||||
|
|
||||||
minimizeMenu() {
|
minimizeMenu() {
|
||||||
this.state = 'minimized';
|
this.state = "minimized";
|
||||||
this.container.classList.add(STATES.minimized);
|
this.container.classList.add(STATES.minimized);
|
||||||
}
|
}
|
||||||
|
|
||||||
hideMenu() {
|
hideMenu() {
|
||||||
this.state = 'hidden';
|
this.state = "hidden";
|
||||||
this.container.setAttribute('aria-expanded', true);
|
this.container.setAttribute("aria-expanded", true);
|
||||||
this.container.classList.remove(STATES.visible);
|
this.container.classList.remove(STATES.visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Menu from './menu';
|
import Menu from "./menu";
|
||||||
|
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
|
|
||||||
@@ -10,105 +10,105 @@ const menuHtml = `
|
|||||||
<span class="menu__text">Open menu</span>
|
<span class="menu__text">Open menu</span>
|
||||||
</button>`;
|
</button>`;
|
||||||
|
|
||||||
describe('Menu button', () => {
|
describe("Menu button", () => {
|
||||||
let menu;
|
let menu;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = menuHtml;
|
document.body.innerHTML = menuHtml;
|
||||||
menu = new Menu({
|
menu = new Menu({
|
||||||
container: document.querySelector('.menu'),
|
container: document.querySelector(".menu"),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should initialise', () => {
|
it("Should initialise", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
expect(menu).toMatchObject({});
|
expect(menu).toMatchObject({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should fail to initialise if container is missing', () => {
|
it("Should fail to initialise if container is missing", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
expect((new Menu()).state).toBeUndefined();
|
expect(new Menu().state).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should default to visible state', () => {
|
it("Should default to visible state", () => {
|
||||||
expect(menu.state).toBe('visible');
|
expect(menu.state).toBe("visible");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be hidden initially', () => {
|
it("Should be hidden initially", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
expect(menu.container.classList.contains('is-visible')).toBe(false);
|
expect(menu.container.classList.contains("is-visible")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be visible after 1 second', () => {
|
it("Should be visible after 1 second", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
|
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 1000);
|
||||||
expect(menu.container.classList.contains('is-visible')).toBe(true);
|
expect(menu.container.classList.contains("is-visible")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Menu can be shown', () => {
|
test("Menu can be shown", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.showMenu();
|
menu.showMenu();
|
||||||
expect(menu.state).toBe('visible');
|
expect(menu.state).toBe("visible");
|
||||||
expect(menu.container.classList.contains('is-visible')).toBe(true);
|
expect(menu.container.classList.contains("is-visible")).toBe(true);
|
||||||
expect(menu.container.classList.contains('is-minimized')).toBe(false);
|
expect(menu.container.classList.contains("is-minimized")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Menu can be hidden', () => {
|
test("Menu can be hidden", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.hideMenu();
|
menu.hideMenu();
|
||||||
expect(menu.state).toBe('hidden');
|
expect(menu.state).toBe("hidden");
|
||||||
expect(menu.container.classList.contains('is-visible')).toBe(false);
|
expect(menu.container.classList.contains("is-visible")).toBe(false);
|
||||||
expect(menu.container.classList.contains('is-minimized')).toBe(false);
|
expect(menu.container.classList.contains("is-minimized")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Menu can be minimized', () => {
|
test("Menu can be minimized", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.minimizeMenu();
|
menu.minimizeMenu();
|
||||||
expect(menu.state).toBe('minimized');
|
expect(menu.state).toBe("minimized");
|
||||||
expect(menu.container.classList.contains('is-visible')).toBe(false);
|
expect(menu.container.classList.contains("is-visible")).toBe(false);
|
||||||
expect(menu.container.classList.contains('is-minimized')).toBe(true);
|
expect(menu.container.classList.contains("is-minimized")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('The state should not change on scroll if it is hidden', () => {
|
test("The state should not change on scroll if it is hidden", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.hideMenu();
|
menu.hideMenu();
|
||||||
menu.updateState(10, 0);
|
menu.updateState(10, 0);
|
||||||
expect(menu.state).toBe('hidden');
|
expect(menu.state).toBe("hidden");
|
||||||
menu.updateState(0, 10);
|
menu.updateState(0, 10);
|
||||||
expect(menu.state).toBe('hidden');
|
expect(menu.state).toBe("hidden");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('The state should change to minimized when scrolling down', () => {
|
test("The state should change to minimized when scrolling down", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.showMenu();
|
menu.showMenu();
|
||||||
menu.updateState(0, 10);
|
menu.updateState(0, 10);
|
||||||
expect(menu.state).toBe('minimized');
|
expect(menu.state).toBe("minimized");
|
||||||
});
|
});
|
||||||
|
|
||||||
test('The state should change to visible when scrolling up', () => {
|
test("The state should change to visible when scrolling up", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.minimizeMenu();
|
menu.minimizeMenu();
|
||||||
menu.updateState(10, 0);
|
menu.updateState(10, 0);
|
||||||
expect(menu.state).toBe('visible');
|
expect(menu.state).toBe("visible");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should have initial ARIA attributes', () => {
|
it("Should have initial ARIA attributes", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
expect(menu.container.getAttribute('aria-haspopup')).toBe('true');
|
expect(menu.container.getAttribute("aria-haspopup")).toBe("true");
|
||||||
expect(menu.container.getAttribute('aria-expanded')).toBe('false');
|
expect(menu.container.getAttribute("aria-expanded")).toBe("false");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should have updated ARIA attribute when menu is opened', () => {
|
it("Should have updated ARIA attribute when menu is opened", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.showMenu();
|
menu.showMenu();
|
||||||
expect(menu.container.getAttribute('aria-expanded')).toBe('false');
|
expect(menu.container.getAttribute("aria-expanded")).toBe("false");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should have updated ARIA attribute when menu is closed', () => {
|
it("Should have updated ARIA attribute when menu is closed", () => {
|
||||||
menu.init();
|
menu.init();
|
||||||
menu.showMenu();
|
menu.showMenu();
|
||||||
menu.hideMenu();
|
menu.hideMenu();
|
||||||
expect(menu.container.getAttribute('aria-expanded')).toBe('true');
|
expect(menu.container.getAttribute("aria-expanded")).toBe("true");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,53 +1,55 @@
|
|||||||
const STATES = {
|
const STATES = {
|
||||||
open: 'is-open',
|
open: "is-open",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Navigation {
|
export default class Navigation {
|
||||||
constructor(cfg = {}) {
|
constructor(cfg = {}) {
|
||||||
if (!cfg.container) return false;
|
if (!cfg.container) return false;
|
||||||
if (!cfg.menu) return false;
|
if (!cfg.menu) return false;
|
||||||
this.state = 'hidden';
|
this.state = "hidden";
|
||||||
this.container = cfg.container;
|
this.container = cfg.container;
|
||||||
this.menu = cfg.menu;
|
this.menu = cfg.menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
if (!this.state) return false;
|
if (!this.state) return false;
|
||||||
this.container.setAttribute('aria-hidden', true);
|
this.container.setAttribute("aria-hidden", true);
|
||||||
this.attachClickEvents();
|
this.attachClickEvents();
|
||||||
this.attachKeyEvents();
|
this.attachKeyEvents();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
attachClickEvents() {
|
attachClickEvents() {
|
||||||
this.container.addEventListener('click', (e) => {
|
this.container.addEventListener("click", e => {
|
||||||
if (this.container === e.target) {
|
if (this.container === e.target) {
|
||||||
this.closeNav();
|
this.closeNav();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.menu.container.addEventListener('click', () => {
|
this.menu.container.addEventListener("click", () => {
|
||||||
this.openNav();
|
this.openNav();
|
||||||
});
|
});
|
||||||
this.container.querySelector('.nav__close').addEventListener('click', () => {
|
this.container
|
||||||
|
.querySelector(".nav__close")
|
||||||
|
.addEventListener("click", () => {
|
||||||
this.closeNav();
|
this.closeNav();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
attachKeyEvents() {
|
attachKeyEvents() {
|
||||||
const first = this.container.querySelector('.nav__link');
|
const first = this.container.querySelector(".nav__link");
|
||||||
const last = this.container.querySelector('.nav__close');
|
const last = this.container.querySelector(".nav__close");
|
||||||
this.container.addEventListener('keydown', (e) => {
|
this.container.addEventListener("keydown", e => {
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
this.closeNav();
|
this.closeNav();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
first.addEventListener('keydown', (e) => {
|
first.addEventListener("keydown", e => {
|
||||||
if (e.shiftKey && e.keyCode === 9) {
|
if (e.shiftKey && e.keyCode === 9) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
last.focus();
|
last.focus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
last.addEventListener('keydown', (e) => {
|
last.addEventListener("keydown", e => {
|
||||||
if (!e.shiftKey && e.keyCode === 9) {
|
if (!e.shiftKey && e.keyCode === 9) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
first.focus();
|
first.focus();
|
||||||
@@ -57,18 +59,18 @@ export default class Navigation {
|
|||||||
|
|
||||||
openNav() {
|
openNav() {
|
||||||
this.lastActiveElement = document.activeElement;
|
this.lastActiveElement = document.activeElement;
|
||||||
this.state = 'visible';
|
this.state = "visible";
|
||||||
this.menu.hideMenu();
|
this.menu.hideMenu();
|
||||||
this.container.classList.add(STATES.open);
|
this.container.classList.add(STATES.open);
|
||||||
this.container.setAttribute('aria-hidden', false);
|
this.container.setAttribute("aria-hidden", false);
|
||||||
this.container.querySelector('.nav__title-link').focus();
|
this.container.querySelector(".nav__title-link").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeNav() {
|
closeNav() {
|
||||||
this.state = 'hidden';
|
this.state = "hidden";
|
||||||
this.menu.showMenu();
|
this.menu.showMenu();
|
||||||
this.container.classList.remove(STATES.open);
|
this.container.classList.remove(STATES.open);
|
||||||
this.container.setAttribute('aria-hidden', true);
|
this.container.setAttribute("aria-hidden", true);
|
||||||
if (this.lastActiveElement) {
|
if (this.lastActiveElement) {
|
||||||
this.lastActiveElement.focus();
|
this.lastActiveElement.focus();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Navigation from './navigation';
|
import Navigation from "./navigation";
|
||||||
|
|
||||||
const navHtml = `<a href="/test">Test link</a>
|
const navHtml = `<a href="/test">Test link</a>
|
||||||
<nav class="nav">
|
<nav class="nav">
|
||||||
@@ -26,140 +26,140 @@ beforeEach(() => {
|
|||||||
document.body.innerHTML = navHtml;
|
document.body.innerHTML = navHtml;
|
||||||
// Mock Menu
|
// Mock Menu
|
||||||
const menu = {
|
const menu = {
|
||||||
container: document.querySelector('.menu'),
|
container: document.querySelector(".menu"),
|
||||||
showMenu: jest.fn(),
|
showMenu: jest.fn(),
|
||||||
hideMenu: jest.fn(),
|
hideMenu: jest.fn(),
|
||||||
};
|
};
|
||||||
nav = new Navigation({
|
nav = new Navigation({
|
||||||
container: document.querySelector('.nav'),
|
container: document.querySelector(".nav"),
|
||||||
menu,
|
menu,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Navigation', () => {
|
describe("Navigation", () => {
|
||||||
it('Should initialise', () => {
|
it("Should initialise", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
expect(nav).toMatchObject({});
|
expect(nav).toMatchObject({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should fail to initialise if container is missing', () => {
|
it("Should fail to initialise if container is missing", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
expect((new Navigation()).state).toBeUndefined();
|
expect(new Navigation().state).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should fail to initialise if the menu is not provided', () => {
|
it("Should fail to initialise if the menu is not provided", () => {
|
||||||
const noMenu = new Navigation({
|
const noMenu = new Navigation({
|
||||||
container: document.querySelector('.nav'),
|
container: document.querySelector(".nav"),
|
||||||
});
|
});
|
||||||
noMenu.init();
|
noMenu.init();
|
||||||
expect(noMenu.state).toBeUndefined();
|
expect(noMenu.state).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should be hidden by default', () => {
|
it("Should be hidden by default", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
expect(nav.container.classList.contains('is-open')).toBe(false);
|
expect(nav.container.classList.contains("is-open")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should close when the .nav element is clicked', () => {
|
it("Should close when the .nav element is clicked", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
nav.container.dispatchEvent(event);
|
nav.container.dispatchEvent(event);
|
||||||
expect(nav.state).toBe('hidden');
|
expect(nav.state).toBe("hidden");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should close when the user presses ESC', () => {
|
it("Should close when the user presses ESC", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
const event = new Event('keydown');
|
const event = new Event("keydown");
|
||||||
event.keyCode = 27;
|
event.keyCode = 27;
|
||||||
nav.container.dispatchEvent(event);
|
nav.container.dispatchEvent(event);
|
||||||
expect(nav.state).toBe('hidden');
|
expect(nav.state).toBe("hidden");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should not close when the .nav__content element is clicked', () => {
|
it("Should not close when the .nav__content element is clicked", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
nav.container.querySelector('.nav__content').dispatchEvent(event);
|
nav.container.querySelector(".nav__content").dispatchEvent(event);
|
||||||
expect(nav.state).toBe('visible');
|
expect(nav.state).toBe("visible");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should have initial ARIA attributes', () => {
|
it("Should have initial ARIA attributes", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
expect(nav.container.getAttribute('aria-hidden')).toBe('true');
|
expect(nav.container.getAttribute("aria-hidden")).toBe("true");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should update the ARIA attributes when visible', () => {
|
it("Should update the ARIA attributes when visible", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
expect(nav.container.getAttribute('aria-hidden')).toBe('false');
|
expect(nav.container.getAttribute("aria-hidden")).toBe("false");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should update the ARIA attributes when hidden', () => {
|
it("Should update the ARIA attributes when hidden", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
nav.closeNav();
|
nav.closeNav();
|
||||||
expect(nav.container.getAttribute('aria-hidden')).toBe('true');
|
expect(nav.container.getAttribute("aria-hidden")).toBe("true");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Navigation menu button', () => {
|
describe("Navigation menu button", () => {
|
||||||
it('Should open the Navigation when clicked', () => {
|
it("Should open the Navigation when clicked", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
nav.menu.container.dispatchEvent(event);
|
nav.menu.container.dispatchEvent(event);
|
||||||
expect(nav.state).toBe('visible');
|
expect(nav.state).toBe("visible");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Navigation close button', () => {
|
describe("Navigation close button", () => {
|
||||||
it('Should close the Navigation when clicked', () => {
|
it("Should close the Navigation when clicked", () => {
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
nav.container.querySelector('.nav__close').dispatchEvent(event);
|
nav.container.querySelector(".nav__close").dispatchEvent(event);
|
||||||
expect(nav.state).toBe('hidden');
|
expect(nav.state).toBe("hidden");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Navigation focus behaviour', () => {
|
describe("Navigation focus behaviour", () => {
|
||||||
let first;
|
let first;
|
||||||
let last;
|
let last;
|
||||||
let menu;
|
let menu;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
menu = nav.container.querySelector('.menu');
|
menu = nav.container.querySelector(".menu");
|
||||||
first = nav.container.querySelector('.nav__link');
|
first = nav.container.querySelector(".nav__link");
|
||||||
last = nav.container.querySelector('.nav__close');
|
last = nav.container.querySelector(".nav__close");
|
||||||
menu.focus();
|
menu.focus();
|
||||||
nav.init();
|
nav.init();
|
||||||
nav.openNav();
|
nav.openNav();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should apply focus to .nav__title-link when opened', () => {
|
it("Should apply focus to .nav__title-link when opened", () => {
|
||||||
const link = nav.container.querySelector('.nav__title-link');
|
const link = nav.container.querySelector(".nav__title-link");
|
||||||
expect(document.activeElement).toBe(link);
|
expect(document.activeElement).toBe(link);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Focus moves to first element when TAB pressed on last', () => {
|
test("Focus moves to first element when TAB pressed on last", () => {
|
||||||
last.focus();
|
last.focus();
|
||||||
const event = new Event('keydown');
|
const event = new Event("keydown");
|
||||||
event.keyCode = 9;
|
event.keyCode = 9;
|
||||||
last.dispatchEvent(event);
|
last.dispatchEvent(event);
|
||||||
expect(document.activeElement).toBe(first);
|
expect(document.activeElement).toBe(first);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Focus moves to last element when SHIFT + TAB pressed on first', () => {
|
test("Focus moves to last element when SHIFT + TAB pressed on first", () => {
|
||||||
first.focus();
|
first.focus();
|
||||||
const event = new Event('keydown');
|
const event = new Event("keydown");
|
||||||
event.shiftKey = true;
|
event.shiftKey = true;
|
||||||
event.keyCode = 9;
|
event.keyCode = 9;
|
||||||
first.dispatchEvent(event);
|
first.dispatchEvent(event);
|
||||||
expect(document.activeElement).toBe(last);
|
expect(document.activeElement).toBe(last);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Focus is restored to last active element when Navigation is closed', () => {
|
test("Focus is restored to last active element when Navigation is closed", () => {
|
||||||
first.focus();
|
first.focus();
|
||||||
nav.closeNav();
|
nav.closeNav();
|
||||||
expect(document.activeElement).toBe(menu);
|
expect(document.activeElement).toBe(menu);
|
||||||
|
|||||||
@@ -1,33 +1,37 @@
|
|||||||
export default class ReplyToComment {
|
export default class ReplyToComment {
|
||||||
constructor(cfg = {}) {
|
constructor(cfg = {}) {
|
||||||
if (!cfg.form || cfg.form.className !== 'comments__foot') {
|
if (!cfg.form || cfg.form.className !== "comments__foot") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!cfg.links || cfg.links.length === 0) {
|
if (!cfg.links || cfg.links.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.form = cfg.form;
|
this.form = cfg.form;
|
||||||
this.backupForm = cfg.form.querySelector('#respond').cloneNode(true);
|
this.backupForm = cfg.form.querySelector("#respond").cloneNode(true);
|
||||||
this.links = Array.prototype.slice.call(cfg.links);
|
this.links = Array.prototype.slice.call(cfg.links);
|
||||||
this.links.forEach((link) => {
|
this.links.forEach(link => {
|
||||||
link.addEventListener('click', e => this.handleLinkClick(e, link));
|
link.addEventListener("click", e => this.handleLinkClick(e, link));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
insertForm(container, id, author) {
|
insertForm(container, id, author) {
|
||||||
const form = this.backupForm.cloneNode(true);
|
const form = this.backupForm.cloneNode(true);
|
||||||
const cancel = form.querySelector('#cancel-comment-reply-link');
|
const cancel = form.querySelector("#cancel-comment-reply-link");
|
||||||
form.querySelector('.comment-respond__title-text').innerHTML = `Reply to ${author}`;
|
form.querySelector(
|
||||||
form.querySelector('#submit').value = 'Post reply';
|
".comment-respond__title-text",
|
||||||
form.querySelector('#comment_parent').value = id;
|
).innerHTML = `Reply to ${author}`;
|
||||||
cancel.style.display = 'inline-block';
|
form.querySelector("#submit").value = "Post reply";
|
||||||
cancel.addEventListener('click', e => this.handleCancelClick(e, container));
|
form.querySelector("#comment_parent").value = id;
|
||||||
|
cancel.style.display = "inline-block";
|
||||||
|
cancel.addEventListener("click", e => this.handleCancelClick(e, container));
|
||||||
container.appendChild(form);
|
container.appendChild(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCancelClick(e, container) {
|
handleCancelClick(e, container) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
container.parentNode.querySelector('.comment__reply').classList.remove('is-hidden');
|
container.parentNode
|
||||||
|
.querySelector(".comment__reply")
|
||||||
|
.classList.remove("is-hidden");
|
||||||
while (container.firstChild) {
|
while (container.firstChild) {
|
||||||
container.removeChild(container.firstChild);
|
container.removeChild(container.firstChild);
|
||||||
}
|
}
|
||||||
@@ -36,11 +40,11 @@ export default class ReplyToComment {
|
|||||||
|
|
||||||
handleLinkClick(e, link) {
|
handleLinkClick(e, link) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
link.classList.add('is-hidden');
|
link.classList.add("is-hidden");
|
||||||
while (this.form.firstChild) {
|
while (this.form.firstChild) {
|
||||||
this.form.removeChild(this.form.firstChild);
|
this.form.removeChild(this.form.firstChild);
|
||||||
}
|
}
|
||||||
const container = link.parentNode.querySelector('.comment__inline-reply');
|
const container = link.parentNode.querySelector(".comment__inline-reply");
|
||||||
const { commentId, commentAuthor } = link.dataset;
|
const { commentId, commentAuthor } = link.dataset;
|
||||||
this.insertForm(container, commentId, commentAuthor);
|
this.insertForm(container, commentId, commentAuthor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import ReplyToComment from './reply-to-comment';
|
import ReplyToComment from "./reply-to-comment";
|
||||||
|
|
||||||
const commentHtml = `
|
const commentHtml = `
|
||||||
<div class="comment">
|
<div class="comment">
|
||||||
@@ -66,73 +66,77 @@ let inlineReply;
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = `${commentHtml}${formHtml}`;
|
document.body.innerHTML = `${commentHtml}${formHtml}`;
|
||||||
form = document.querySelector('.comments__foot');
|
form = document.querySelector(".comments__foot");
|
||||||
links = document.querySelectorAll('.comment__reply');
|
links = document.querySelectorAll(".comment__reply");
|
||||||
inlineReply = document.querySelector('.comment__inline-reply');
|
inlineReply = document.querySelector(".comment__inline-reply");
|
||||||
comments = new ReplyToComment({ form, links });
|
comments = new ReplyToComment({ form, links });
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ReplyToComment', () => {
|
describe("ReplyToComment", () => {
|
||||||
it('Should initialise', () => {
|
it("Should initialise", () => {
|
||||||
expect(comments.form).toBeInstanceOf(HTMLDivElement);
|
expect(comments.form).toBeInstanceOf(HTMLDivElement);
|
||||||
expect(comments.links).toBeInstanceOf(Array);
|
expect(comments.links).toBeInstanceOf(Array);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should fail to initialise if form is missing', () => {
|
it("Should fail to initialise if form is missing", () => {
|
||||||
expect(new ReplyToComment()).toEqual({});
|
expect(new ReplyToComment()).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should fail to initialise if there are no links', () => {
|
it("Should fail to initialise if there are no links", () => {
|
||||||
expect(new ReplyToComment({
|
expect(
|
||||||
form: document.querySelector('#respond'),
|
new ReplyToComment({
|
||||||
})).toEqual({});
|
form: document.querySelector("#respond"),
|
||||||
expect(new ReplyToComment({
|
}),
|
||||||
form: document.querySelector('#respond'),
|
).toEqual({});
|
||||||
links: document.querySelectorAll('.no-links-here'),
|
expect(
|
||||||
})).toEqual({});
|
new ReplyToComment({
|
||||||
|
form: document.querySelector("#respond"),
|
||||||
|
links: document.querySelectorAll(".no-links-here"),
|
||||||
|
}),
|
||||||
|
).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should remove the form from the DOM when a reply link is clicked', () => {
|
it("Should remove the form from the DOM when a reply link is clicked", () => {
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
comments.handleLinkClick(event, links[0]);
|
comments.handleLinkClick(event, links[0]);
|
||||||
expect(form.innerHTML).toEqual('');
|
expect(form.innerHTML).toEqual("");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should hide the link when it is clicked', () => {
|
it("Should hide the link when it is clicked", () => {
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
comments.handleLinkClick(event, links[0]);
|
comments.handleLinkClick(event, links[0]);
|
||||||
expect(links[0].classList.contains('is-hidden')).toBe(true);
|
expect(links[0].classList.contains("is-hidden")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should insert the form into the inline reply container', () => {
|
it("Should insert the form into the inline reply container", () => {
|
||||||
comments.insertForm(inlineReply);
|
comments.insertForm(inlineReply);
|
||||||
const inlineForm = inlineReply.querySelectorAll('form');
|
const inlineForm = inlineReply.querySelectorAll("form");
|
||||||
expect(inlineForm.length).toEqual(1);
|
expect(inlineForm.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should update the comment_parent hidden element', () => {
|
it("Should update the comment_parent hidden element", () => {
|
||||||
comments.insertForm(inlineReply, '123', 'Mr Smith');
|
comments.insertForm(inlineReply, "123", "Mr Smith");
|
||||||
const { value } = inlineReply.querySelector('#comment_parent');
|
const { value } = inlineReply.querySelector("#comment_parent");
|
||||||
expect(value).toEqual('123');
|
expect(value).toEqual("123");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should add a cancel link to the inline form', () => {
|
it("Should add a cancel link to the inline form", () => {
|
||||||
comments.insertForm(inlineReply);
|
comments.insertForm(inlineReply);
|
||||||
const el = inlineReply.querySelector('#cancel-comment-reply-link');
|
const el = inlineReply.querySelector("#cancel-comment-reply-link");
|
||||||
expect(el.style.display).toEqual('inline-block');
|
expect(el.style.display).toEqual("inline-block");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should restore the reply link when the cancel link is clicked', () => {
|
it("Should restore the reply link when the cancel link is clicked", () => {
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
comments.insertForm(inlineReply);
|
comments.insertForm(inlineReply);
|
||||||
comments.handleCancelClick(event, inlineReply);
|
comments.handleCancelClick(event, inlineReply);
|
||||||
expect(links[0].classList.contains('is-hidden')).toBe(false);
|
expect(links[0].classList.contains("is-hidden")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should remove the inline form when the cancel link is clicked', () => {
|
it("Should remove the inline form when the cancel link is clicked", () => {
|
||||||
const event = new Event('click');
|
const event = new Event("click");
|
||||||
comments.insertForm(inlineReply);
|
comments.insertForm(inlineReply);
|
||||||
comments.handleCancelClick(event, inlineReply);
|
comments.handleCancelClick(event, inlineReply);
|
||||||
expect(inlineReply.innerHTML).toEqual('');
|
expect(inlineReply.innerHTML).toEqual("");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
21
js/windy.js
21
js/windy.js
@@ -1,30 +1,31 @@
|
|||||||
import Menu from './menu';
|
import Menu from "./menu";
|
||||||
import Navigation from './navigation';
|
import Navigation from "./navigation";
|
||||||
import Image from './image';
|
import Image from "./image";
|
||||||
import ReplyToComment from './reply-to-comment';
|
import ReplyToComment from "./reply-to-comment";
|
||||||
|
|
||||||
const windy = {
|
const windy = {
|
||||||
images: [],
|
images: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function init() {
|
export default function init() {
|
||||||
Array.prototype.slice.call(document.querySelectorAll('img'))
|
Array.prototype.slice
|
||||||
.forEach((image) => {
|
.call(document.querySelectorAll("img"))
|
||||||
|
.forEach(image => {
|
||||||
const img = new Image(image);
|
const img = new Image(image);
|
||||||
img.start();
|
img.start();
|
||||||
windy.images.push(img);
|
windy.images.push(img);
|
||||||
});
|
});
|
||||||
windy.menu = new Menu({
|
windy.menu = new Menu({
|
||||||
container: document.querySelector('.menu'),
|
container: document.querySelector(".menu"),
|
||||||
});
|
});
|
||||||
windy.navigation = new Navigation({
|
windy.navigation = new Navigation({
|
||||||
container: document.querySelector('.nav'),
|
container: document.querySelector(".nav"),
|
||||||
menu: windy.menu,
|
menu: windy.menu,
|
||||||
});
|
});
|
||||||
windy.menu.init();
|
windy.menu.init();
|
||||||
windy.navigation.init();
|
windy.navigation.init();
|
||||||
windy.comments = new ReplyToComment({
|
windy.comments = new ReplyToComment({
|
||||||
form: document.querySelector('.comments__foot'),
|
form: document.querySelector(".comments__foot"),
|
||||||
links: document.querySelectorAll('.comment__reply'),
|
links: document.querySelectorAll(".comment__reply"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
15849
package-lock.json
generated
15849
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "windycoys",
|
"name": "windycoys",
|
||||||
"version": "1.0.0-RC.3",
|
"version": "1.0.0-RC.8",
|
||||||
"description": "Wordpress theme for windycoys.com",
|
"description": "Wordpress theme for windycoys.com",
|
||||||
"author": "Dan Head <me@danielhead.com>",
|
"author": "Dan Head <me@danielhead.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -12,13 +12,13 @@
|
|||||||
"build": "run-s images css:compile js:compile",
|
"build": "run-s images css:compile js:compile",
|
||||||
"css": "run-p -c css:*",
|
"css": "run-p -c css:*",
|
||||||
"css:compile": "postcss -o theme/style.css css/index.css",
|
"css:compile": "postcss -o theme/style.css css/index.css",
|
||||||
"css:lint": "stylelint --config .stylelintrc \"css/**/*.css\"",
|
"css:lint": "stylelint css/*.css",
|
||||||
"images": "node build/imagemin.js",
|
"images": "node build/imagemin.js",
|
||||||
"jest": "jest",
|
"jest": "jest",
|
||||||
"jest:watch": "jest --watch",
|
"jest:watch": "jest --watch",
|
||||||
"js": "run-s js:*",
|
"js": "run-s js:*",
|
||||||
"js:compile": "rollup --config rollup.config.js",
|
"js:compile": "rollup --config rollup.config.js",
|
||||||
"js:lint": "eslint js/",
|
"js:lint": "eslint build js",
|
||||||
"serve": "node build/serve.js",
|
"serve": "node build/serve.js",
|
||||||
"start": "run-p watch serve",
|
"start": "run-p watch serve",
|
||||||
"test": "run-s css:lint js:lint jest",
|
"test": "run-s css:lint js:lint jest",
|
||||||
@@ -27,43 +27,67 @@
|
|||||||
"watch:images": "nodemon -q --watch images -e png,jpg,gif --exec npm run images",
|
"watch:images": "nodemon -q --watch images -e png,jpg,gif --exec npm run images",
|
||||||
"watch:js": "nodemon -q --watch js -e js --exec npm run js"
|
"watch:js": "nodemon -q --watch js -e js --exec npm run js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"browser-sync": "^2.26.3",
|
|
||||||
"docker-compose": "^0.9.3",
|
|
||||||
"mysql": "^2.16.0",
|
|
||||||
"nodemon": "^1.18.7",
|
|
||||||
"pre-commit": "^1.2.2"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/cli": "^7.2.3",
|
"@babel/cli": "^7.10.3",
|
||||||
"@babel/core": "^7.2.0",
|
"@babel/core": "^7.10.3",
|
||||||
"@babel/preset-env": "^7.2.3",
|
"@babel/preset-env": "^7.10.3",
|
||||||
"babel-core": "^7.0.0-bridge.0",
|
"babel-core": "^7.0.0-bridge.0",
|
||||||
"babel-jest": "^23.6.0",
|
"babel-jest": "^26.1.0",
|
||||||
"cssnano": "^4.1.8",
|
"browser-sync": "^2.26.7",
|
||||||
"eslint": "^5.12.0",
|
"cssnano": "^4.1.10",
|
||||||
"eslint-config-airbnb-base": "^13.1.0",
|
"docker-compose": "^0.12.0",
|
||||||
"eslint-plugin-import": "^2.14.0",
|
"eslint": "^5.16.0",
|
||||||
|
"eslint-config-airbnb-base": "^13.2.0",
|
||||||
|
"eslint-config-prettier": "^4.3.0",
|
||||||
|
"eslint-plugin-import": "^2.21.2",
|
||||||
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
|
"husky": "^1.3.1",
|
||||||
"imagemin": "^6.1.0",
|
"imagemin": "^6.1.0",
|
||||||
"imagemin-gifsicle": "^6.0.1",
|
"imagemin-gifsicle": "^6.0.1",
|
||||||
"imagemin-jpegtran": "^6.0.0",
|
"imagemin-jpegtran": "^6.0.0",
|
||||||
"imagemin-pngquant": "^7.0.0",
|
"imagemin-pngquant": "^7.0.0",
|
||||||
"jest": "^23.6.0",
|
"jest": "^26.1.0",
|
||||||
|
"lint-staged": "^8.2.1",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
|
"nodemon": "^2.0.4",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss-banner": "^3.0.0",
|
"postcss-banner": "^3.0.2",
|
||||||
"postcss-cli": "^6.1.1",
|
"postcss-cli": "^7.1.1",
|
||||||
"postcss-import": "^12.0.1",
|
"postcss-import": "^12.0.1",
|
||||||
"postcss-normalize": "^7.0.1",
|
"postcss-normalize": "^7.0.1",
|
||||||
"postcss-preset-env": "^6.4.0",
|
"postcss-preset-env": "^6.7.0",
|
||||||
"rollup": "^1.1.0",
|
"prettier": "^1.19.1",
|
||||||
"rollup-plugin-babel": "^4.3.0",
|
"rollup": "^1.32.1",
|
||||||
"rollup-plugin-uglify": "^6.0.1",
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
"stylelint": "^9.9.0",
|
"rollup-plugin-uglify": "^6.0.4",
|
||||||
"stylelint-config-standard": "^18.0.0"
|
"stylelint": "^13.6.1",
|
||||||
|
"stylelint-config-prettier": "^5.3.0",
|
||||||
|
"stylelint-config-standard": "^18.3.0",
|
||||||
|
"stylelint-prettier": "^1.1.2"
|
||||||
},
|
},
|
||||||
"pre-commit": [
|
"husky": {
|
||||||
"test"
|
"hooks": {
|
||||||
|
"pre-commit": "lint-staged"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"build/*.js": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write",
|
||||||
|
"git add"
|
||||||
],
|
],
|
||||||
|
"css/*.css": [
|
||||||
|
"stylelint --fix",
|
||||||
|
"prettier --write",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
|
"js/*.js": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write",
|
||||||
|
"jest",
|
||||||
|
"git add"
|
||||||
|
]
|
||||||
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 1 version",
|
"last 1 version",
|
||||||
"not dead",
|
"not dead",
|
||||||
|
|||||||
@@ -31,3 +31,5 @@ window.twttr = (function(d, s, id) {
|
|||||||
};
|
};
|
||||||
return t;
|
return t;
|
||||||
}(document, "script", "twitter-wjs"));</script>
|
}(document, "script", "twitter-wjs"));</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
@@ -151,6 +151,23 @@ function windycoys_is_ie() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function windycoys_first_sentence($string) {
|
||||||
|
$sentence = preg_split( '/(\.|!|\?)\s/', $string, 2, PREG_SPLIT_DELIM_CAPTURE );
|
||||||
|
return $sentence['0'] . $sentence['1'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function windycoys_get_description($post_id) {
|
||||||
|
if (get_post_type() == "post") {
|
||||||
|
$post = get_post($post_id);
|
||||||
|
$content = (strlen($post->post_excerpt) === 0) ?
|
||||||
|
strip_tags(windycoys_first_sentence($post->post_content)) :
|
||||||
|
$post->post_excerpt;
|
||||||
|
return $content;
|
||||||
|
} else {
|
||||||
|
return get_bloginfo('description');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function windycoys_jetpack_custom_image($media, $post_id, $args) {
|
function windycoys_jetpack_custom_image($media, $post_id, $args) {
|
||||||
if ($media) {
|
if ($media) {
|
||||||
return $media;
|
return $media;
|
||||||
@@ -169,3 +186,11 @@ function windycoys_jetpack_custom_image($media, $post_id, $args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_filter('jetpack_images_get_images', 'windycoys_jetpack_custom_image', 10, 3);
|
add_filter('jetpack_images_get_images', 'windycoys_jetpack_custom_image', 10, 3);
|
||||||
|
|
||||||
|
function windycoys_strip_scripts(&$scripts) {
|
||||||
|
if(!is_admin()){
|
||||||
|
$scripts->remove('jquery');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_filter('wp_default_scripts', 'windycoys_strip_scripts');
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ $manifest = get_template_directory_uri() . '/manifest.json';
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="<?php bloginfo('charset'); ?>">
|
<meta charset="<?php bloginfo('charset'); ?>">
|
||||||
<title><?php wp_title(''); ?><?php if(wp_title('', false)) { echo ' « '; } ?> <?php bloginfo('name'); ?></title>
|
<title><?php wp_title(''); ?><?php if(wp_title('', false)) { echo ' « '; } ?> <?php bloginfo('name'); ?></title>
|
||||||
|
<meta name="description" content="<?php echo windycoys_get_description(get_the_id()) ?>">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="theme-color" content="#201f42">
|
<meta name="theme-color" content="#201f42">
|
||||||
<?php wp_head(); ?>
|
<?php wp_head(); ?>
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
<div class="social">
|
<div class="social">
|
||||||
|
<div class="social__item">
|
||||||
<a class="social__link" href="https://www.facebook.com/WindyCOYS/" aria-label="WindyCOYS on Facebook">
|
<a class="social__link" href="https://www.facebook.com/WindyCOYS/" aria-label="WindyCOYS on Facebook">
|
||||||
<svg class="icon icon--facebook" aria-hidden="true">
|
<svg class="icon icon--facebook" aria-hidden="true">
|
||||||
<use xlink:href="#icon-facebook"></use>
|
<use xlink:href="#icon-facebook"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="social__item">
|
||||||
<a class="social__link" href="https://twitter.com/windycoys/" aria-label="WindyCOYS on Twitter">
|
<a class="social__link" href="https://twitter.com/windycoys/" aria-label="WindyCOYS on Twitter">
|
||||||
<svg class="icon icon--twitter" aria-hidden="true">
|
<svg class="icon icon--twitter" aria-hidden="true">
|
||||||
<use xlink:href="#icon-twitter"></use>
|
<use xlink:href="#icon-twitter"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="social__item">
|
||||||
<a class="social__link" href="/feed" aria-label="WindyCOYS RSS Feed">
|
<a class="social__link" href="/feed" aria-label="WindyCOYS RSS Feed">
|
||||||
<svg class="icon icon--rss" aria-hidden="true">
|
<svg class="icon icon--rss" aria-hidden="true">
|
||||||
<use xlink:href="#icon-rss"></use>
|
<use xlink:href="#icon-rss"></use>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="social__item">
|
||||||
|
<?php echo do_shortcode('[paypal-donation]'); ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user