Initial commit
28
.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
b-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.gz
|
||||
|
||||
pids
|
||||
logs
|
||||
results
|
||||
|
||||
npm-debug.log
|
||||
node_modules
|
||||
package-lock.json
|
||||
|
||||
.idea/*
|
||||
*.iml
|
||||
projectFilesBackup
|
||||
|
||||
.DS_Store
|
||||
|
||||
dist/
|
||||
|
||||
config.json
|
||||
changelog.md
|
||||
changelog.md.bk
|
2
assets/built/casper.js
Normal file
1
assets/built/casper.js.map
Normal file
2
assets/built/screen.css
Normal file
1
assets/built/screen.css.map
Normal file
597
assets/css/screen.css
Normal file
@ -0,0 +1,597 @@
|
||||
/* 1. Variables */
|
||||
|
||||
:root {
|
||||
--color-white: #fff;
|
||||
--color-lighter-gray: #f6f6f6;
|
||||
--color-light-gray: #e6e6e6;
|
||||
--color-mid-gray: #ccc;
|
||||
--color-dark-gray: #444;
|
||||
--color-darker-gray: #15171a;
|
||||
--color-black: #000;
|
||||
--color-primary-text: var(--color-darker-gray);
|
||||
--color-secondary-text: rgba(0, 0, 0, 0.4);
|
||||
--color-border: rgba(0, 0, 0, 0.08);
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
--font-serif: Georgia, Times, serif;
|
||||
--font-mono: Menlo, Courier, monospace;
|
||||
--gap: clamp(24px, 1.7032rem + 1.9355vw, 48px);
|
||||
}
|
||||
|
||||
/* 2. Resets */
|
||||
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
}
|
||||
|
||||
body {
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
img, picture, video, canvas, svg {
|
||||
display: block;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
iframe {
|
||||
display: block;
|
||||
}
|
||||
|
||||
input, button, textarea, select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
p, h1, h2, h3, h4, h5, h6 {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
/* 3. Globals */
|
||||
|
||||
body {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-darker-gray);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* 4. Layout */
|
||||
|
||||
.gh-viewport {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.gh-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.gh-outer {
|
||||
position: relative;
|
||||
padding: 0 max(4vmin, 20px);
|
||||
}
|
||||
|
||||
.gh-inner {
|
||||
margin: 0 auto;
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 5. Navigation */
|
||||
|
||||
.gh-navigation {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.gh-navigation-inner {
|
||||
display: grid;
|
||||
grid-auto-flow: row dense;
|
||||
column-gap: 24px;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.gh-navigation-brand {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.gh-navigation-logo {
|
||||
position: relative;
|
||||
font-size: 2.6rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.015em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gh-navigation-logo img {
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
.gh-navigation-menu,
|
||||
.gh-navigation-members a[data-portal="signin"] {
|
||||
font-size: 1.6rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.gh-navigation-menu {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.gh-navigation .nav {
|
||||
display: inline-flex;
|
||||
gap: 24px;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.gh-navigation .gh-more-toggle {
|
||||
position: relative;
|
||||
margin: 0 -6px;
|
||||
font-size: inherit;
|
||||
text-transform: inherit;
|
||||
}
|
||||
|
||||
.gh-navigation .gh-more-toggle svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.gh-navigation-actions {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.gh-navigation-members {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.gh-navigation-members .gh-button {
|
||||
font-size: inherit;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.gh-search {
|
||||
margin-right: -6px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.gh-search:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.gh-navigation-brand .gh-search {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.gh-navigation-members {
|
||||
flex-direction: column-reverse;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gh-navigation-actions .gh-search {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.gh-navigation-brand .gh-search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gh-navigation:not(.is-dropdown-loaded) .gh-navigation-menu .nav > li {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5.1. Navigation variants */
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
LOGO Home About Collection Author Portal Login Subscribe
|
||||
======================================================================
|
||||
*/
|
||||
|
||||
.is-navigation-left-logo .gh-navigation-inner {
|
||||
grid-template-columns: auto 1fr auto;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.is-navigation-left-logo .gh-navigation-menu {
|
||||
margin-right: 64px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
Home About Collection LOGO Login Subscribe
|
||||
======================================================================
|
||||
*/
|
||||
|
||||
.is-navigation-middle-logo .gh-navigation-inner {
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
}
|
||||
|
||||
.is-navigation-middle-logo .gh-navigation-brand {
|
||||
grid-column-start: 2;
|
||||
}
|
||||
|
||||
.is-navigation-middle-logo .gh-navigation-actions {
|
||||
gap: 28px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.is-navigation-middle-logo .gh-navigation-menu {
|
||||
margin-right: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
Search LOGO Login Subscribe
|
||||
Home About Collection Author Portal
|
||||
======================================================================
|
||||
*/
|
||||
|
||||
.is-navigation-stacked.gh-navigation {
|
||||
position: relative;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-inner {
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-brand {
|
||||
display: flex;
|
||||
grid-row-start: 1;
|
||||
grid-column-start: 2;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.is-navigation-stacked .gh-navigation-inner {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-menu {
|
||||
grid-row-start: 2;
|
||||
grid-column: 1 / 4;
|
||||
justify-content: center;
|
||||
height: 56px;
|
||||
margin: 0 48px;
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-menu::before,
|
||||
.is-navigation-stacked .gh-navigation-menu::after {
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
content: "";
|
||||
background-color: var(--color-border);
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-menu::after {
|
||||
top: 136px;
|
||||
}
|
||||
|
||||
.is-navigation-stacked .gh-navigation-actions {
|
||||
grid-row-start: 1;
|
||||
grid-column: 1 / 4;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5.2. Dropdown menu */
|
||||
|
||||
.gh-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: -16px;
|
||||
z-index: 90;
|
||||
width: 200px;
|
||||
padding: 12px 0;
|
||||
margin-top: 24px;
|
||||
text-align: left;
|
||||
visibility: hidden;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04), 0 7px 20px -5px rgba(0, 0, 0, 0.15);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s, transform 0.2s;
|
||||
transform: translate3d(0, 6px, 0);
|
||||
}
|
||||
|
||||
.is-navigation-middle-logo .gh-dropdown {
|
||||
right: auto;
|
||||
left: -24px;
|
||||
}
|
||||
|
||||
.is-dropdown-mega .gh-dropdown {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-flow: column;
|
||||
column-gap: 40px;
|
||||
width: auto;
|
||||
padding: 20px 32px;
|
||||
}
|
||||
|
||||
.is-dropdown-open .gh-dropdown {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.gh-dropdown li a {
|
||||
display: block;
|
||||
padding: 6px 20px;
|
||||
color: #15171a !important;
|
||||
}
|
||||
|
||||
.is-dropdown-mega .gh-dropdown li a {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
/* 5.3. Burger icon */
|
||||
|
||||
.gh-burger {
|
||||
position: relative;
|
||||
display: none;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0;
|
||||
margin-right: -3px;
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.gh-burger::before,
|
||||
.gh-burger::after {
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
width: 24px;
|
||||
height: 1px;
|
||||
content: "";
|
||||
background-color: var(--color-darker-gray);
|
||||
transition: all 0.2s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
|
||||
}
|
||||
|
||||
.gh-burger::before {
|
||||
top: 11px;
|
||||
}
|
||||
|
||||
.gh-burger::after {
|
||||
bottom: 11px;
|
||||
}
|
||||
|
||||
.is-navigation-open .gh-burger::before {
|
||||
top: 15px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.is-navigation-open .gh-burger::after {
|
||||
bottom: 14px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.gh-burger {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5.4. Mobile menu */
|
||||
|
||||
@media (max-width: 767px) {
|
||||
#gh-navigation {
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
#gh-navigation .gh-navigation-inner {
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 48px;
|
||||
}
|
||||
|
||||
#gh-navigation .gh-navigation-brand {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
grid-column-start: 1;
|
||||
align-items: center;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
#gh-navigation .gh-navigation-logo {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
#gh-navigation .gh-navigation-menu,
|
||||
#gh-navigation .gh-navigation-actions {
|
||||
position: fixed;
|
||||
justify-content: center;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#gh-navigation .gh-navigation-menu {
|
||||
transition: none;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
#gh-navigation .nav {
|
||||
gap: 20px;
|
||||
align-items: center;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
#gh-navigation .nav a {
|
||||
font-size: 2.6rem;
|
||||
font-weight: 600;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
#gh-navigation .nav li {
|
||||
opacity: 0;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
#gh-navigation .gh-navigation-actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#gh-navigation :is(.gh-button, a[data-portal="signin"]) {
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
}
|
||||
|
||||
#gh-navigation .gh-button {
|
||||
width: 100%;
|
||||
font-size: 1.8rem;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
#gh-navigation a[data-portal="signin"] {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
#gh-main {
|
||||
transition: opacity 0.4s;
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 3999999;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation .gh-navigation-menu,
|
||||
.is-navigation-open#gh-navigation .gh-navigation-actions {
|
||||
position: static;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation .nav {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation .nav li {
|
||||
opacity: 1;
|
||||
transition: transform 0.2s, opacity 0.2s;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation .gh-navigation-actions {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: var(--gap) 0 calc(var(--gap) + 8px);
|
||||
background-color: var(--color-white);
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation :is(.gh-button, a[data-portal="signin"]) {
|
||||
opacity: 1;
|
||||
transition: transform 0.4s, opacity 0.4s;
|
||||
transition-delay: 0.2s;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-navigation a[data-portal="signin"] {
|
||||
transition-delay: 0.4s;
|
||||
}
|
||||
|
||||
.is-navigation-open#gh-main {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.gh-button {
|
||||
display: inline-flex;
|
||||
gap: 0.4em;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.75em 1.15em;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
color: var(--color-white);
|
||||
letter-spacing: inherit;
|
||||
cursor: pointer;
|
||||
background-color: var(--ghost-accent-color);
|
||||
border: 0;
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
.gh-button:hover {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
.gh-icon-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
color: var(--color-darker-gray);
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.gh-icon-button svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
102
assets/js/casper.js
Normal file
@ -0,0 +1,102 @@
|
||||
/* Dropdown menu */
|
||||
(function () {
|
||||
const mediaQuery = window.matchMedia('(max-width: 767px)');
|
||||
|
||||
const head = document.querySelector('.gh-navigation');
|
||||
const menu = head.querySelector('.gh-navigation-menu');
|
||||
const nav = menu?.querySelector('.nav');
|
||||
if (!nav) return;
|
||||
|
||||
const logo = document.querySelector('.gh-navigation-logo');
|
||||
const navHTML = nav.innerHTML;
|
||||
|
||||
if (mediaQuery.matches) {
|
||||
const items = nav.querySelectorAll('li');
|
||||
items.forEach(function (item, index) {
|
||||
item.style.transitionDelay = `${0.03 * (index + 1)}s`;
|
||||
});
|
||||
}
|
||||
|
||||
const makeDropdown = function () {
|
||||
if (mediaQuery.matches) return;
|
||||
const submenuItems = [];
|
||||
|
||||
while ((nav.offsetWidth + 64) > menu.offsetWidth) {
|
||||
if (nav.lastElementChild) {
|
||||
submenuItems.unshift(nav.lastElementChild);
|
||||
nav.lastElementChild.remove();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!submenuItems.length) {
|
||||
head.classList.add('is-dropdown-loaded');
|
||||
return;
|
||||
}
|
||||
|
||||
const toggle = document.createElement('button');
|
||||
toggle.setAttribute('class', 'gh-more-toggle gh-icon-button');
|
||||
toggle.setAttribute('aria-label', 'More');
|
||||
toggle.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="currentColor"><path d="M21.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM13.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM5.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0z"></path></svg>';
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.setAttribute('class', 'gh-dropdown');
|
||||
|
||||
if (submenuItems.length >= 10) {
|
||||
head.classList.add('is-dropdown-mega');
|
||||
wrapper.style.gridTemplateRows = `repeat(${Math.ceil(submenuItems.length / 2)}, 1fr)`;
|
||||
} else {
|
||||
head.classList.remove('is-dropdown-mega');
|
||||
}
|
||||
|
||||
submenuItems.forEach(function (child) {
|
||||
wrapper.appendChild(child);
|
||||
});
|
||||
|
||||
toggle.appendChild(wrapper);
|
||||
nav.appendChild(toggle);
|
||||
|
||||
head.classList.add('is-dropdown-loaded');
|
||||
|
||||
window.addEventListener('click', function (e) {
|
||||
if (head.classList.contains('is-dropdown-open')) {
|
||||
head.classList.remove('is-dropdown-open');
|
||||
} else if (toggle.contains(e.target)) {
|
||||
head.classList.add('is-dropdown-open');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
imagesLoaded(logo, function () {
|
||||
makeDropdown();
|
||||
});
|
||||
|
||||
window.addEventListener('load', function () {
|
||||
if (!logo) {
|
||||
makeDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('resize', function () {
|
||||
setTimeout(() => {
|
||||
nav.innerHTML = navHTML;
|
||||
makeDropdown();
|
||||
}, 1);
|
||||
});
|
||||
})();
|
||||
|
||||
/* Mobile menu burger toggle */
|
||||
(function () {
|
||||
const navigation = document.querySelector('.gh-navigation');
|
||||
const burger = navigation.querySelector('.gh-burger');
|
||||
if (!burger) return;
|
||||
|
||||
burger.addEventListener('click', function () {
|
||||
if (!navigation.classList.contains('is-navigation-open')) {
|
||||
navigation.classList.add('is-navigation-open');
|
||||
} else {
|
||||
navigation.classList.remove('is-navigation-open');
|
||||
}
|
||||
});
|
||||
})();
|
7
assets/js/lib/imagesloaded.pkgd.min.js
vendored
Normal file
0
author.hbs
Normal file
38
default.hbs
Normal file
@ -0,0 +1,38 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{@site.locale}}">
|
||||
<head>
|
||||
|
||||
{{!-- Basic meta - advanced meta is output with {{ghost_head}} below --}}
|
||||
<title>{{meta_title}}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
{{!-- Preload main styles and scripts for better performance --}}
|
||||
<link rel="preload" as="style" href="{{asset "built/screen.css"}}">
|
||||
<link rel="preload" as="script" href="{{asset "built/casper.js"}}">
|
||||
|
||||
{{!-- Theme assets - use the {{asset}} helper to reference styles & scripts, this will take care of caching and cache-busting automatically --}}
|
||||
<link rel="stylesheet" type="text/css" href="{{asset "built/screen.css"}}">
|
||||
|
||||
{{!-- This tag outputs all your advanced SEO meta, structured data, and other important settings, it should always be the last tag before the closing head tag --}}
|
||||
{{ghost_head}}
|
||||
|
||||
</head>
|
||||
<body class="{{body_class}}">
|
||||
|
||||
<div class="gh-viewport">
|
||||
|
||||
{{> "components/navigation" navigationLayout=@custom.navigation_layout}}
|
||||
|
||||
{{{body}}}
|
||||
|
||||
</div>
|
||||
|
||||
{{!-- Scripts - handle responsive videos, infinite scroll, and navigation dropdowns --}}
|
||||
<script src="{{asset "built/casper.js"}}"></script>
|
||||
|
||||
{{!-- Ghost outputs required functional scripts with this tag, it should always be the last thing before the closing body tag --}}
|
||||
{{ghost_foot}}
|
||||
|
||||
</body>
|
||||
</html>
|
174
gulpfile.js
Normal file
@ -0,0 +1,174 @@
|
||||
const {series, watch, src, dest, parallel} = require('gulp');
|
||||
const pump = require('pump');
|
||||
const path = require('path');
|
||||
const releaseUtils = require('@tryghost/release-utils');
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
// gulp plugins and utils
|
||||
const livereload = require('gulp-livereload');
|
||||
const postcss = require('gulp-postcss');
|
||||
const zip = require('gulp-zip');
|
||||
const concat = require('gulp-concat');
|
||||
const uglify = require('gulp-uglify');
|
||||
const beeper = require('beeper');
|
||||
const fs = require('fs');
|
||||
|
||||
// postcss plugins
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const cssnano = require('cssnano');
|
||||
const easyimport = require('postcss-easy-import');
|
||||
|
||||
const REPO = 'TryGhost/Casper';
|
||||
const REPO_READONLY = 'TryGhost/Casper';
|
||||
const CHANGELOG_PATH = path.join(process.cwd(), '.', 'changelog.md');
|
||||
|
||||
function serve(done) {
|
||||
livereload.listen();
|
||||
done();
|
||||
}
|
||||
|
||||
const handleError = (done) => {
|
||||
return function (err) {
|
||||
if (err) {
|
||||
beeper();
|
||||
}
|
||||
return done(err);
|
||||
};
|
||||
};
|
||||
|
||||
function hbs(done) {
|
||||
pump([
|
||||
src(['*.hbs', 'partials/**/*.hbs']),
|
||||
livereload()
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
function css(done) {
|
||||
pump([
|
||||
src('assets/css/screen.css', {sourcemaps: true}),
|
||||
postcss([
|
||||
easyimport,
|
||||
autoprefixer(),
|
||||
cssnano()
|
||||
]),
|
||||
dest('assets/built/', {sourcemaps: '.'}),
|
||||
livereload()
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
function js(done) {
|
||||
pump([
|
||||
src([
|
||||
// pull in lib files first so our own code can depend on it
|
||||
'assets/js/lib/*.js',
|
||||
'assets/js/*.js'
|
||||
], {sourcemaps: true}),
|
||||
concat('casper.js'),
|
||||
uglify(),
|
||||
dest('assets/built/', {sourcemaps: '.'}),
|
||||
livereload()
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
function zipper(done) {
|
||||
const filename = require('./package.json').name + '.zip';
|
||||
|
||||
pump([
|
||||
src([
|
||||
'**',
|
||||
'!node_modules', '!node_modules/**',
|
||||
'!dist', '!dist/**',
|
||||
'!yarn-error.log',
|
||||
'!yarn.lock',
|
||||
'!gulpfile.js'
|
||||
]),
|
||||
zip(filename),
|
||||
dest('dist/')
|
||||
], handleError(done));
|
||||
}
|
||||
|
||||
const cssWatcher = () => watch('assets/css/**', css);
|
||||
const jsWatcher = () => watch('assets/js/**', js);
|
||||
const hbsWatcher = () => watch(['*.hbs', 'partials/**/*.hbs'], hbs);
|
||||
const watcher = parallel(cssWatcher, jsWatcher, hbsWatcher);
|
||||
const build = series(css, js);
|
||||
|
||||
exports.build = build;
|
||||
exports.zip = series(build, zipper);
|
||||
exports.default = series(build, serve, watcher);
|
||||
|
||||
exports.release = async () => {
|
||||
// @NOTE: https://yarnpkg.com/lang/en/docs/cli/version/
|
||||
// require(./package.json) can run into caching issues, this re-reads from file everytime on release
|
||||
let packageJSON = JSON.parse(fs.readFileSync('./package.json'));
|
||||
const newVersion = packageJSON.version;
|
||||
|
||||
if (!newVersion || newVersion === '') {
|
||||
console.log(`Invalid version: ${newVersion}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`\nCreating release for ${newVersion}...`);
|
||||
|
||||
const githubToken = process.env.GST_TOKEN;
|
||||
|
||||
if (!githubToken) {
|
||||
console.log('Please configure your environment with a GitHub token located in GST_TOKEN');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await inquirer.prompt([{
|
||||
type: 'input',
|
||||
name: 'compatibleWithGhost',
|
||||
message: 'Which version of Ghost is it compatible with?',
|
||||
default: '5.0.0'
|
||||
}]);
|
||||
|
||||
const compatibleWithGhost = result.compatibleWithGhost;
|
||||
|
||||
const releasesResponse = await releaseUtils.releases.get({
|
||||
userAgent: 'Casper',
|
||||
uri: `https://api.github.com/repos/${REPO_READONLY}/releases`
|
||||
});
|
||||
|
||||
if (!releasesResponse || !releasesResponse) {
|
||||
console.log('No releases found. Skipping...');
|
||||
return;
|
||||
}
|
||||
|
||||
let previousVersion = releasesResponse[0].tag_name || releasesResponse[0].name;
|
||||
console.log(`Previous version: ${previousVersion}`);
|
||||
|
||||
const changelog = new releaseUtils.Changelog({
|
||||
changelogPath: CHANGELOG_PATH,
|
||||
folder: path.join(process.cwd(), '.')
|
||||
});
|
||||
|
||||
changelog
|
||||
.write({
|
||||
githubRepoPath: `https://github.com/${REPO}`,
|
||||
lastVersion: previousVersion
|
||||
})
|
||||
.sort()
|
||||
.clean();
|
||||
|
||||
const newReleaseResponse = await releaseUtils.releases.create({
|
||||
draft: true,
|
||||
preRelease: false,
|
||||
tagName: 'v' + newVersion,
|
||||
releaseName: newVersion,
|
||||
userAgent: 'Casper',
|
||||
uri: `https://api.github.com/repos/${REPO}/releases`,
|
||||
github: {
|
||||
token: githubToken
|
||||
},
|
||||
content: [`**Compatible with Ghost ≥ ${compatibleWithGhost}**\n\n`],
|
||||
changelogPath: CHANGELOG_PATH
|
||||
});
|
||||
console.log(`\nRelease draft generated: ${newReleaseResponse.releaseUrl}\n`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
2
index.hbs
Normal file
@ -0,0 +1,2 @@
|
||||
{{!< default}}
|
||||
{{!-- The tag above means: insert everything in this file into the body of the default.hbs template --}}
|
104
package.json
Normal file
@ -0,0 +1,104 @@
|
||||
{
|
||||
"name": "casper-2023",
|
||||
"description": "A default theme for the Ghost publishing platform",
|
||||
"demo": "https://demo.ghost.io",
|
||||
"version": "6.0.0",
|
||||
"engines": {
|
||||
"ghost": ">=5.0.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "gulp",
|
||||
"zip": "gulp zip",
|
||||
"test": "gscan .",
|
||||
"test:ci": "gscan --fatal --verbose .",
|
||||
"pretest": "gulp build",
|
||||
"preship": "yarn test",
|
||||
"ship": "STATUS=$(git status --porcelain); echo $STATUS; if [ -z \"$STATUS\" ]; then yarn version && git push --follow-tags; else echo \"Uncomitted changes found.\" && exit 1; fi",
|
||||
"postship": "git fetch && gulp release"
|
||||
},
|
||||
"author": {
|
||||
"name": "Ghost Foundation",
|
||||
"email": "hello@ghost.org",
|
||||
"url": "https://ghost.org/"
|
||||
},
|
||||
"gpm": {
|
||||
"type": "theme",
|
||||
"categories": [
|
||||
"Minimal",
|
||||
"Magazine"
|
||||
]
|
||||
},
|
||||
"keywords": [
|
||||
"ghost",
|
||||
"theme",
|
||||
"ghost-theme"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/TryGhost/Casper.git"
|
||||
},
|
||||
"bugs": "https://github.com/TryGhost/Casper/issues",
|
||||
"contributors": "https://github.com/TryGhost/Casper/graphs/contributors",
|
||||
"devDependencies": {
|
||||
"@tryghost/release-utils": "0.8.1",
|
||||
"autoprefixer": "10.4.7",
|
||||
"beeper": "2.1.0",
|
||||
"cssnano": "5.1.12",
|
||||
"gscan": "4.36.1",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-livereload": "4.0.2",
|
||||
"gulp-postcss": "9.0.1",
|
||||
"gulp-uglify": "3.0.2",
|
||||
"gulp-zip": "5.1.0",
|
||||
"inquirer": "8.2.4",
|
||||
"postcss": "8.2.13",
|
||||
"postcss-color-mod-function": "3.0.3",
|
||||
"postcss-easy-import": "4.0.0",
|
||||
"pump": "3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"config": {
|
||||
"posts_per_page": 25,
|
||||
"image_sizes": {
|
||||
"xxs": {
|
||||
"width": 30
|
||||
},
|
||||
"xs": {
|
||||
"width": 100
|
||||
},
|
||||
"s": {
|
||||
"width": 300
|
||||
},
|
||||
"m": {
|
||||
"width": 600
|
||||
},
|
||||
"l": {
|
||||
"width": 1000
|
||||
},
|
||||
"xl": {
|
||||
"width": 2000
|
||||
}
|
||||
},
|
||||
"card_assets": true,
|
||||
"custom": {
|
||||
"navigation_layout": {
|
||||
"type": "select",
|
||||
"options": [
|
||||
"Logo in the middle",
|
||||
"Logo on the left",
|
||||
"Stacked"
|
||||
],
|
||||
"default": "Logo in the middle"
|
||||
}
|
||||
}
|
||||
},
|
||||
"renovate": {
|
||||
"extends": [
|
||||
"@tryghost:theme"
|
||||
]
|
||||
}
|
||||
}
|
50
partials/components/navigation.hbs
Normal file
@ -0,0 +1,50 @@
|
||||
<header id="gh-navigation" class="gh-navigation gh-outer is-navigation-{{#match navigationLayout "Logo on the left"}}left-logo{{else match navigationLayout "Stacked"}}stacked{{else}}middle-logo{{/match}}">
|
||||
<div class="gh-navigation-inner gh-inner">
|
||||
|
||||
<div class="gh-navigation-brand">
|
||||
<a class="gh-navigation-logo" href="{{@site.url}}">
|
||||
{{#if @site.logo}}
|
||||
<img src="{{@site.logo}}" alt="{{@site.title}}">
|
||||
{{else}}
|
||||
{{@site.title}}
|
||||
{{/if}}
|
||||
</a>
|
||||
{{> "search-toggle"}}
|
||||
<button class="gh-burger"></button>
|
||||
</div>
|
||||
|
||||
<nav class="gh-navigation-menu">
|
||||
{{navigation}}
|
||||
{{#unless @site.members_enabled}}
|
||||
{{#match navigationLayout "Stacked"}}
|
||||
{{> "search-toggle"}}
|
||||
{{/match}}
|
||||
{{/unless}}
|
||||
</nav>
|
||||
|
||||
<div class="gh-navigation-actions">
|
||||
{{#unless @site.members_enabled}}
|
||||
{{^match navigationLayout "Stacked"}}
|
||||
{{> "search-toggle"}}
|
||||
{{/match}}
|
||||
{{else}}
|
||||
{{> "search-toggle"}}
|
||||
<div class="gh-navigation-members">
|
||||
{{#unless @member}}
|
||||
{{#unless @site.members_invite_only}}
|
||||
<a href="#/portal/signin" data-portal="signin">Sign in</a>
|
||||
{{#unless hideSubscribeButton}}
|
||||
<a class="gh-button" href="#/portal/signup" data-portal="signup">Subscribe</a>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
<a class="gh-button" href="#/portal/signin" data-portal="signin">Sign in</a>
|
||||
{{/unless}}
|
||||
{{else}}
|
||||
<a class="gh-button" href="#/portal/account" data-portal="account">Account</a>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</header>
|
1
partials/icons/avatar.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M3.513 18.998C4.749 15.504 8.082 13 12 13s7.251 2.504 8.487 5.998C18.47 21.442 15.417 23 12 23s-6.47-1.558-8.487-4.002zM12 12c2.21 0 4-2.79 4-5s-1.79-4-4-4-4 1.79-4 4 1.79 5 4 5z" fill="#FFF"/></g></svg>
|
After Width: | Height: | Size: 308 B |
1
partials/icons/facebook.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M23.9981 11.9991C23.9981 5.37216 18.626 0 11.9991 0C5.37216 0 0 5.37216 0 11.9991C0 17.9882 4.38789 22.9522 10.1242 23.8524V15.4676H7.07758V11.9991H10.1242V9.35553C10.1242 6.34826 11.9156 4.68714 14.6564 4.68714C15.9692 4.68714 17.3424 4.92149 17.3424 4.92149V7.87439H15.8294C14.3388 7.87439 13.8739 8.79933 13.8739 9.74824V11.9991H17.2018L16.6698 15.4676H13.8739V23.8524C19.6103 22.9522 23.9981 17.9882 23.9981 11.9991Z"/></svg>
|
After Width: | Height: | Size: 531 B |
3
partials/icons/fire.hbs
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.49365 4.58752C3.53115 6.03752 2.74365 7.70002 2.74365 9.25002C2.74365 10.6424 3.29678 11.9778 4.28134 12.9623C5.26591 13.9469 6.60127 14.5 7.99365 14.5C9.38604 14.5 10.7214 13.9469 11.706 12.9623C12.6905 11.9778 13.2437 10.6424 13.2437 9.25002C13.2437 6.00002 10.9937 3.50002 9.16865 1.68127L6.99365 6.25002L4.49365 4.58752Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 538 B |
11
partials/icons/loader.hbs
Normal file
@ -0,0 +1,11 @@
|
||||
<svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" width="40px" height="40px" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
|
||||
<path opacity="0.2" fill="#000" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946
|
||||
s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634
|
||||
c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z" />
|
||||
<path fill="#000" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0
|
||||
C22.32,8.481,24.301,9.057,26.013,10.047z">
|
||||
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20"
|
||||
dur="0.5s" repeatCount="indefinite" />
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 923 B |
5
partials/icons/lock.hbs
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16.25 6.875H3.75C3.40482 6.875 3.125 7.15482 3.125 7.5V16.25C3.125 16.5952 3.40482 16.875 3.75 16.875H16.25C16.5952 16.875 16.875 16.5952 16.875 16.25V7.5C16.875 7.15482 16.5952 6.875 16.25 6.875Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M7.1875 6.875V4.0625C7.1875 3.31658 7.48382 2.60121 8.01126 2.07376C8.53871 1.54632 9.25408 1.25 10 1.25C10.7459 1.25 11.4613 1.54632 11.9887 2.07376C12.5162 2.60121 12.8125 3.31658 12.8125 4.0625V6.875" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M10 13.125C10.6904 13.125 11.25 12.5654 11.25 11.875C11.25 11.1846 10.6904 10.625 10 10.625C9.30964 10.625 8.75 11.1846 8.75 11.875C8.75 12.5654 9.30964 13.125 10 13.125Z" fill="currentColor"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 932 B |
1
partials/icons/rss.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><circle cx="6.18" cy="17.82" r="2.18"/><path d="M4 4.44v2.83c7.03 0 12.73 5.7 12.73 12.73h2.83c0-8.59-6.97-15.56-15.56-15.56zm0 5.66v2.83c3.9 0 7.07 3.17 7.07 7.07h2.83c0-5.47-4.43-9.9-9.9-9.9z"/></svg>
|
After Width: | Height: | Size: 263 B |
1
partials/icons/search.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" width="20" height="20"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
After Width: | Height: | Size: 248 B |
1
partials/icons/twitter.hbs
Normal file
@ -0,0 +1 @@
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M23.954 4.569c-.885.389-1.83.654-2.825.775 1.014-.611 1.794-1.574 2.163-2.723-.951.555-2.005.959-3.127 1.184-.896-.959-2.173-1.559-3.591-1.559-2.717 0-4.92 2.203-4.92 4.917 0 .39.045.765.127 1.124C7.691 8.094 4.066 6.13 1.64 3.161c-.427.722-.666 1.561-.666 2.475 0 1.71.87 3.213 2.188 4.096-.807-.026-1.566-.248-2.228-.616v.061c0 2.385 1.693 4.374 3.946 4.827-.413.111-.849.171-1.296.171-.314 0-.615-.03-.916-.086.631 1.953 2.445 3.377 4.604 3.417-1.68 1.319-3.809 2.105-6.102 2.105-.39 0-.779-.023-1.17-.067 2.189 1.394 4.768 2.209 7.557 2.209 9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63.961-.689 1.8-1.56 2.46-2.548l-.047-.02z"/></svg>
|
After Width: | Height: | Size: 752 B |
1
partials/search-toggle.hbs
Normal file
@ -0,0 +1 @@
|
||||
<button class="gh-search gh-icon-button" aria-label="Search this site" data-ghost-search>{{> "icons/search"}}</button>
|