Implemented build process for assets.

This commit is contained in:
flash 2023-10-13 19:33:34 +00:00
parent 93bd735a06
commit e2454e1002
28 changed files with 2433 additions and 1377 deletions

3
.gitignore vendored
View file

@ -3,5 +3,6 @@
/.debug
/config/*.ini
/vendor
/aaaapublic/assets
/node_modules
/public/assets
/assets/current.json

115
assets/2021.css/clock.css Normal file
View file

@ -0,0 +1,115 @@
.clock {
width: 200px;
height: 200px;
border-radius: 100%;
border: 4px solid #c0c0c0;
overflow: hidden;
box-sizing: content-box;
filter: drop-shadow(0 1px 5px #000);
}
.clock-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #fffd;
filter: blur(20px);
}
.clock-center {
position: absolute;
top: 96px;
left: 96px;
width: 8px;
height: 8px;
background-color: #000;
border-radius: 100%;
z-index: 1000;
}
.clock-hand {
--hand-rotation: 0deg;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: rotate(var(--hand-rotation));
z-index: 900;
}
.clock-hand-display {
position: absolute;
width: 2px;
left: 99px;
height: 99px;
background-color: #000;
}
.clock-hand-hours {
z-index: 910;
}
.clock-hand-minutes {
z-index: 920;
}
.clock-hand-seconds {
z-index: 930;
}
.clock-hand-hours .clock-hand-display {
height: 70px;
margin-top: 30px;
filter: drop-shadow(0 1px 2px #000);
}
.clock-hand-minutes .clock-hand-display {
height: 80px;
margin-top: 20px;
filter: drop-shadow(0 1px 3px #000);
}
.clock-hand-seconds .clock-hand-display {
height: 100px;
margin-top: 15px;
opacity: .6;
background-color: #f00;
filter: drop-shadow(0 1px 4px #000);
}
.clock-number {
position: absolute;
top: 0;
left: 0;
z-index: 500;
width: 100px;
height: 100px;
}
.clock-number-display {
position: absolute;
width: 2px;
height: 10px;
background-color: #000;
}
.clock-number-9 .clock-number-display,
.clock-number-3 .clock-number-display {
width: 10px;
height: 2px;
}
.clock-number-6 .clock-number-display {
bottom: 0;
}
.clock-number-12 .clock-number-display {
right: 0;
height: 15px;
}
.clock-number-3 .clock-number-display {
right: 0;
bottom: 0;
}
.clock-number-12 {
left: 1px;
}
.clock-number-9 {
top: 99px;
}
.clock-number-6 {
top: 100px;
left: 99px;
}
.clock-number-3 {
top: 1px;
left: 100px;
}

View file

@ -0,0 +1,60 @@
.index-featured {
display: grid;
grid-template-columns: 1fr 1fr;
flex: 1 1 auto;
overflow: hidden;
margin: 5px auto;
padding: 0 10px;
margin-bottom: 0;
column-gap: 10px;
row-gap: 10px;
width: 100%;
max-width: 1000px;
}
@media(max-width: 900px) { .index-featured { grid-template-columns: 1fr; overflow: visible; } }
.index-feature {
overflow: auto;
scrollbar-width: thin;
}
.index-feature-header {
border-bottom: 1px solid #333;
display: flex;
align-items: center;
}
.index-feature-header-link {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.index-feature-header-title {
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
font-size: 2em;
line-height: 1.5em;
pointer-events: none;
flex: 1 1 auto;
}
.index-feature-header-more {
pointer-events: none;
flex: 0 0 auto;
margin: 0 5px;
padding: 2px 8px;
border-radius: 2em;
font-size: .9em;
line-height: 1.5em;
background-color: #1a1a1a;
transition: background-color .2s;
}
.index-feature-header-more::after {
content: " »";
}
.index-feature-header:focus-within .index-feature-header-more,
.index-feature-header:hover .index-feature-header-more,
.index-feature-header-more:focus {
background-color: #2a2a2a;
}
.index-feature-header:active .index-feature-header-more,
.index-feature-header-more:active {
background-color: #222;
}

View file

100
assets/2021.css/home.css Normal file
View file

@ -0,0 +1,100 @@
.php {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
z-index: 177;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
pointer-events: none;
}
.php-search {
max-width: 600px;
width: 100%;
pointer-events: initial;
}
.php-search-input {
border: 1px solid #999;
background-color: #fff;
opacity: .5;
box-shadow: 0 2px .5em #000a, inset 0 1px 2px #000a;
transition: opacity .5s, box-shadow .5s;
}
.php-search-input:hover,
.php-search-input:focus,
.php-search-input:focus-within {
opacity: 1;
box-shadow: 0 2px 1em #000, inset 0 1px 2px #000a;
}
.php-search-input input {
border-width: 0;
background-color: transparent;
color: #000;
font-family: Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
font-size: 24px;
line-height: 35px;
width: 100%;
height: 100%;
padding: 2px 5px;
}
.php-time {
display: flex;
justify-content: center;
align-items: center;
margin: 20px auto;
width: 100%;
}
.php-time-analog {
flex: 0 0 auto;
}
.php-time-alter {
flex: 0 0 auto;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 300px;
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
filter: drop-shadow(0 1px 5px #000);
color: transparent;
}
.php-time-digital {
font-size: 7em;
line-height: 1.5em;
display: flex;
flex: 0 0 auto;
max-width: 300px;
width: 100%;
align-items: center;
justify-content: center;
}
.php-time-date {
font-size: 2em;
}
.php-time-digital-separator {
margin-top: -4px;
}
.php-time-digital-separator-hidden {
visibility: hidden;
}
.php-time-digital-hours,
.php-time-digital-separator,
.php-date-label {
background-image: linear-gradient(180deg, #eee 0%, #ddd 50%, #ccc 50%, #aaa 100%);
background-clip: text;
-webkit-background-clip: text;
}
.php-time-digital-minutes,
.php-date-week,
.php-date-day,
.php-date-month,
.php-date-year {
background-image: linear-gradient(0deg, #281430 0%, #392540 50%, #4a3650 50%, #6c5871 100%);
background-clip: text;
-webkit-background-clip: text;
}

47
assets/2021.css/index.css Normal file
View file

@ -0,0 +1,47 @@
.index {
display: flex;
flex-direction: column;
height: 100%;
max-height: 100vh;
overflow: hidden;
}
@media(max-width: 900px) { .index {
max-height: initial;
overflow: auto;
} }
.index-menu {
width: 100%;
display: flex;
justify-content: center;
background-image: linear-gradient(0deg, #111 0%, #222 50%, #333 50%, #555 100%);
flex: 0 0 auto;
box-shadow: 0 0 1em rgba(0, 0, 0, .8);
}
.index-menu a {
display: block;
color: #fff;
text-decoration: none;
font-size: 1.5em;
line-height: 1.2em;
padding: 5px 10px;
transition: background-color .1s;
}
.index-menu a:hover,
.index-menu a:focus {
background-color: rgba(255, 255, 255, .1);
}
.index-menu a:active {
background-color: rgba(127, 127, 127, .1);
}
@media (max-width: 600px) {
.index-menu {
flex-wrap: wrap;
}
.index-menu a {
min-width: 200px;
margin: 2px;
padding: 10px;
text-align: center;
}
}

274
assets/2021.css/main.css Normal file
View file

@ -0,0 +1,274 @@
html {
scrollbar-color: #4a3650 #111;
}
pre, code {
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
}
/* an attempt to replicate scrollbar-color for chromosome */
::-webkit-scrollbar {
width: 6px;
background-color: #111;
}
::-webkit-scrollbar-thumb {
background-color: #4a3650;
}
::-webkit-scrollbar-thumb:hover {
background-color: #5b4761;
}
::-webkit-scrollbar-thumb:active {
background-color: #6c5872;
}
body {
background-color: #111;
color: #fff;
font: 12px/20px Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
display: flex;
flex-direction: column;
}
@include sprite.css;
.header, .footer { flex: 0 0 auto; }
.container { flex: 1 1 auto; }
.header {
width: 100%;
height: 200px;
overflow: hidden;
transition: height .5s;
}
.header-minimal .header {
height: auto;
}
@media (max-width: 700px) {
.header { height: auto; }
}
.index .header {
height: 50vh;
}
.fullscreen-header .header {
height: 100%;
}
.header-background {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
overflow: hidden;
}
.header-background img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
filter: blur(20px) brightness(80%);
transform: scale(1.2);
opacity: 1;
transition: opacity .5s;
}
.header-foreground {
width: 100%;
height: 100%;
display: flex;
max-width: 1200px;
margin: 0 auto;
justify-content: space-between;
align-items: flex-end;
padding: 10px;
}
.header-minimal .header-foreground {
align-items: center;
}
@media (max-width: 700px) {
.header-foreground {
justify-content: center;
align-items: center;
flex-direction: column;
}
}
.index .header-foreground {
align-items: center;
justify-content: flex-end;
flex-direction: column;
}
.header-logo {
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
font-size: 3em;
line-height: 1.2em;
filter: drop-shadow(0 1px 5px #000);
color: transparent;
text-decoration: none;
display: flex;
flex: 0 0 auto;
}
.index .header-logo {
font-size: 5em;
}
.header-flash {
background-image: linear-gradient(180deg, #eee 0%, #ddd 50%, #ccc 50%, #aaa 100%);
background-clip: text;
-webkit-background-clip: text;
white-space: pre;
}
.header-wave {
background-image: linear-gradient(0deg, #281430 0%, #392540 50%, #4a3650 50%, #6c5871 100%);
-webkit-background-clip: text;
white-space: pre;
}
.header-right {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.header-menu {
display: flex;
justify-content: center;
flex: 0 0 auto;
margin-top: 10px;
}
.header-minimal .header-menu {
margin-top: 0;
}
.index .header-menu,
.fullscreen-header .header-menu,
.now-playing .header-menu {
display: none;
}
.header-menu a {
display: block;
color: #fff;
text-decoration: none;
font-size: 1.5em;
line-height: 1.2em;
margin: 0 2px;
padding: 5px 10px;
border-radius: 5px;
text-shadow: 0 1px 5px #000;
transition: background-color .1s;
}
.header-menu a:hover,
.header-menu a:focus {
background-color: rgba(255, 255, 255, .1);
}
.header-menu a:active {
background-color: rgba(127, 127, 127, .1);
}
@media (max-width: 800px) {
.header-menu {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}
.header-menu a {
text-align: center;
min-width: 150px;
margin: 2px;
padding: 10px 0;
}
.header-menu :first-child {
display: none;
}
}
@media (max-width: 480px) {
.header-menu { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 320px) {
.header-menu { grid-template-columns: 1fr; }
}
.footer {}
.index .footer,
.fullscreen-header .footer,
.now-playing .footer {
display: none;
}
.footer-text {
opacity: .2;
font-size: .9em;
text-align: center;
max-width: 1200px;
margin: 5px auto;
}
@include index.css;
.header-now-playing {
max-height: 60px;
min-width: 300px;
max-width: 500px;
height: 100%;
background-image: linear-gradient(0deg, #111c 0%, #222c 50%, #333c 50%, #555c 100%);
box-shadow: 0 2px 1em #000;
border-radius: 5px;
overflow: hidden;
align-items: center;
bottom: 0;
padding: 5px;
display: grid;
grid-template-columns: 25px 50px 1fr;
column-gap: 5px;
transition: bottom .5s, width .2s, max-height .5s, padding .2s;
}
.header-now-playing-hidden {
bottom: -80px;
max-height: 0;
padding: 0;
}
.header-now-playing-icon img {
vertical-align: middle;
}
.header-now-playing-cover {
width: 50px;
height: 50px;
}
.header-now-playing-cover img {
width: 100%;
height: 100%;
vertical-align: middle;
object-fit: cover;
}
.header-now-playing-details {
overflow: hidden;
white-space: nowrap;
}
.header-now-playing-details a {
color: #fff;
text-decoration: none;
transition: width .2s;
}
.header-now-playing-details a:hover,
.header-now-playing-details a:focus {
text-decoration: underline;
}
.header-now-playing-title {
font-size: 1.2em;
}
.header-now-playing-title,
.header-now-playing-artist {
overflow: hidden;
text-overflow: ellipsis;
}
.http-error {
text-align: center;
}
.http-error-head {
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
font-size: 2.5em;
line-height: 2em;
font-weight: 400;
}
@include featured.css;
@include section.css;
@include socials.css;
@include project.css;
@include home.css;
@include clock.css;

126
assets/2021.css/project.css Normal file
View file

@ -0,0 +1,126 @@
.project {
padding: 0 10px;
/*background-color: var(--project-colour);
background-image: linear-gradient(#111e, #111e);
overflow: hidden;*/
}
.project-content {
max-width: 1100px;
width: 100%;
margin: 1em auto;
overflow: hidden;
background-color: var(--project-colour);
background-image: linear-gradient(180deg, #555c 0, #333c 38px, #222c 38px, #111c 100%);
box-shadow: 0 2px 1em #000;
border-radius: 5px;
}
.project-languages {
font-size: 0;
line-height: 0;
display: inline-block;
font-family: Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
margin-left: 4px;
}
.project-language {
font-size: 11px;
line-height: 18px;
display: inline-block;
border-left: 4px solid var(--language-colour);
background-color: var(--language-colour);
background-image: linear-gradient(90deg, #1118, #111a);
border-radius: 4px;
overflow: hidden;
padding: 0 4px;
margin: 0 4px;
box-shadow: 0 0 1px var(--language-colour);
}
.project-details {
margin: 10px;
margin-bottom: 0;
}
.project-details h2 {
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
font-size: 2em;
line-height: 1em;
font-weight: 400;
margin-bottom: 5px;
}
.project-details p {
font-size: .9em;
line-height: 1.8em;
}
.project-details .project-details-summary {
font-size: 1.2em;
line-height: 1.5em;
}
.project-links {
display: flex;
margin: 0 3px;
}
.project-link {
margin: 4px 1px;
color: #fff;
text-decoration: none;
min-width: 100px;
padding: 2px 8px;
border-radius: 4px;
transition: background-color .2s;
}
.project-link:hover,
.project-link:active {
background-color: #fff2;
}
.project-link:focus {
background-color: #fff1;
}
.index-project {
margin: 5px;
background-image: linear-gradient(180deg, #555c 0, #333c 32px, #222c 32px, #111c 100%);
box-shadow: 0 2px 5px #000;
border-radius: 5px;
overflow: hidden;
}
.index-project-anchor {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.index-project-content {
margin: 5px 8px;
margin-bottom: 0;
pointer-events: none;
}
.index-project-name {
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
flex: 1 1 auto;
font-size: 1.5em;
line-height: 1.5em;
}
.index-project-summary {
margin-top: 2px;
}
.index-project-links {
display: flex;
pointer-events: none;
margin: 0 3px;
}
.index-project-link {
pointer-events: initial;
margin: 4px 1px;
color: #fff;
text-decoration: none;
min-width: 100px;
padding: 2px 8px;
border-radius: 4px;
transition: background-color .2s;
}
.index-project-link:hover,
.index-project-link:focus {
background-color: #fff2;
}
.index-project-link:active {
background-color: #fff1;
}

View file

@ -0,0 +1,27 @@
.section {
padding: 0 15px;
}
.section:not(:first-child) {
margin-top: 30px;
}
.section-content {
max-width: 1100px;
margin: 10px auto;
padding: 10px 20px;
filter: drop-shadow(0 1px 5px #000);
}
.section-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(0deg, #111 0%, #222 50%, #333 50%, #555 100%);
transform: skew(-15deg);
}
.section-content h1 {
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
font-size: 2em;
line-height: 1em;
font-weight: 400;
}

View file

@ -0,0 +1,61 @@
.index-contact {
padding: 5px 15px;
overflow: auto;
}
.socials {
max-width: 1100px;
width: 100%;
margin: 10px auto;
padding: 0 15px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
justify-content: space-evenly;
column-gap: 10px;
}
@media(max-width: 980px) { .socials { grid-template-columns: 1fr 1fr; } }
@media(max-width: 640px) { .socials { grid-template-columns: 1fr; } }
.social {
width: 100%;
margin: 5px 0;
filter: drop-shadow(0 1px 5px #000);
cursor: pointer;
display: flex;
align-items: center;
padding: 5px;
}
.index-contact .social {
margin: 10px 0;
}
.social-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(0deg, #1118 0%, #2228 50%, #3338 50%, #5558 100%);
transform: skew(-15deg);
background-color: var(--social-colour);
}
.social:active .social-background {
background-image: linear-gradient(0deg, #1118 0%, #2228 50%, #3338 50%, #3338 100%);
}
.social-icon {
width: 25px;
height: 25px;
margin: 3px 4px 2px 8px;
pointer-events: none;
}
.social-content {
margin: 2px 5px;
pointer-events: none;
}
.social-name {
font-size: .9em;
line-height: 1.5em;
}
.social-handle {
font-size: 1.5em;
line-height: 1.3em;
font-family: 'Electrolize', Verdana, 'Dejavu Sans', Arial, Helvetica, sans-serif;
}

100
assets/ascii.css/main.css Normal file
View file

@ -0,0 +1,100 @@
.ascii-wrap {
margin-bottom: calc(100vh - 70px);
}
.ascii-chars {
text-align: center;
max-width: 1200px;
margin: 0 auto;
}
.ascii-char {
display: inline-flex;
flex-direction: column;
border: 2px solid #4a3650;
border-radius: 5px;
overflow: hidden;
width: 200px;
text-align: left;
margin: 2px;
background-color: #333;
cursor: pointer !important;
transition: background-color .1s;
}
.ascii-char:hover,
.ascii-char:focus {
background-color: #444;
}
.ascii-char:active {
background-color: #222;
}
.ascii-char-print {
white-space: pre;
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
font-size: 2.5em;
text-align: center;
padding: 10px;
pointer-events: none;
}
.ascii-char-desc {
text-align: center;
font-size: 1.2em;
padding: 0 5px 5px;
pointer-events: none;
}
.ascii-char-misc {
display: flex;
justify-content: space-evenly;
border-top: 1px solid #4a3650;
}
.ascii-char-misc-item {
flex: 1 1 auto;
padding: 2px 5px;
transition: background-color .1s;
background-color: #444;
}
.ascii-char-misc-item:not(:last-child) {
border-right: 1px solid #4a3650;
}
.ascii-char-misc-item:hover,
.ascii-char-misc-item:focus {
background-color: #666;
}
.ascii-char-misc-item:active {
background-color: #555;
}
.ascii-char-misc-item-head {
font-variant: small-caps;
}
.ascii-char-misc-item-value {
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
text-align: right;
}
.ascii-search {
padding-top: 10px;
position: sticky;
top: 0;
z-index: 1000;
background-image: linear-gradient(180deg, #4a3650 51px, transparent);
}
.ascii-search-box {
border: 1px solid #000;
border-radius: 5px;
overflow: hidden;
max-width: 1200px;
margin: 0 auto;
}
.ascii-search-box input {
border-width: 0;
background-color: #111;
color: #fff;
width: 100%;
height: 100%;
font-size: 2em;
padding: 5px;
}
.ascii-search-hint {
font-size: .9em;
padding: 0 5px;
transition: opacity .2s;
max-width: 1200px;
margin: 0 auto;
}

75
assets/ascii.js/main.js Normal file
View file

@ -0,0 +1,75 @@
(function() {
var chars = document.getElementsByClassName('ascii-char'),
search = document.getElementById('search');
function charsFilter(filter) {
if(!filter) {
for(var i = 0; i < chars.length; ++i)
chars[i].classList.remove('hidden');
return;
}
filter = filter.toLowerCase();
for(var i = 0; i < chars.length; ++i) {
var chr = chars[i],
code = (chr.dataset.keyCode || 0).toString().toLowerCase(),
print = (chr.dataset.keyPrint || "\0").toString().toLowerCase(),
desc = (chr.dataset.keyDesc || '').toString().toLowerCase(),
html = (chr.dataset.keyHtml || "\0").toString().toLowerCase(),
codeInt = parseInt(code),
isMatch = (filter === 'printable' && (codeInt > 31 && codeInt < 127))
|| (filter === 'control' && (codeInt < 32 || codeInt === 127))
|| code == filter || print == filter
|| html == filter || desc.indexOf(filter) >= 0;
chr.classList[isMatch ? 'remove' : 'add']('hidden');
}
};
window.addEventListener('scroll', function() {
var hidden = document.getElementsByClassName('js-hidden-on-scroll'),
invisible = document.getElementsByClassName('js-invisible-on-scroll'),
atTop = window.scrollY === 0;
for(var i = 0; i < hidden.length; ++i)
hidden[i].classList[atTop ? 'remove' : 'add']('hidden');
for(var i = 0; i < invisible.length; ++i)
invisible[i].classList[atTop ? 'remove' : 'add']('invisible');
});
search.addEventListener('keyup', function() {
location.hash = search.value.trim();
});
window.addEventListener('hashchange', function() {
charsFilter(decodeURIComponent((location.hash || '#').substring(1)));
});
if(location.hash.length > 0) {
search.value = location.hash.substring(1).trim();
charsFilter(search.value);
}
for(var i = 0; i < chars.length; ++i) {
chars[i].addEventListener('click', function(ev) {
var target = ev.target;
while(target !== null && typeof target.dataset.copy === 'undefined') {
target = target.parentNode || null;
if(target.classList.contains('char'))
break;
}
if(target === null || typeof target.dataset.copy === 'undefined')
return;
var doCopy = function() { navigator.clipboard.writeText(target.dataset.copy); };
if(typeof window.mozInnerScreenX !== 'undefined')
doCopy();
else
navigator.permissions.query({name: 'clipboard-write'}).then(function(res) {
if(res.state === 'granted' || res.state === 'prompt')
doCopy();
});
});
}
})();

View file

@ -0,0 +1,21 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
position: relative;
outline-style: none;
}
html, body {
width: 100%;
height: 100%;
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.invisible {
opacity: 0;
}

1
assets/common.js/main.js Normal file
View file

@ -0,0 +1 @@
/* common.js */

100
assets/whois.css/main.css Normal file
View file

@ -0,0 +1,100 @@
.whois-container {
max-width: 1200px;
margin: 0 auto;
}
.whois-lookup-form {
display: flex;
border-radius: 5px;
margin: 10px;
overflow: hidden;
box-shadow: 0 1px 5px #222;
transition: opacity .2s;
}
.whois-locked .whois-lookup-form {
opacity: .5;
}
.whois-lookup-form-input {
display: block;
flex: 1 1 auto;
padding: 10px;
background-color: #212121;
background-image: linear-gradient(0deg, #262626, #202020);
border-width: 0;
color: #fff;
font-family: Tahoma, Geneva, 'Dejavu Sans', Arial, Helvetica, sans-serif;
}
.whois-lookup-form-submit {
flex: 0 0 auto;
background-color: #333333;
background-image: linear-gradient(0deg, transparent, #404040);
color: #fff;
border-width: 0;
padding: 10px;
cursor: pointer;
border-radius: 0;
transition: background-color .2s;
}
.whois-lookup-form-submit:focus,
.whois-lookup-form-submit:hover {
background-color: #3F3F3F;
}
.whois-lookup-form-submit:active {
background-color: #393939;
}
.whois-result {
margin: 10px;
padding: 6px 10px;
white-space: pre-wrap;
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
font-size: 14px;
transition: opacity .2s;
background-color: #202020;
border-radius: 5px;
box-shadow: 0 1px 5px #222;
overflow: auto;
}
.whois-locked .whois-result {
opacity: .5;
}
.whois-result-tabs {
display: flex;
margin: 0 5px;
}
.whois-locked .whois-result-tabs {
opacity: .5;
}
.whois-result-tab {
margin: 0 5px;
padding: 6px 10px;
font-size: 14px;
transition: opacity .2s;
background-color: #202020;
border-radius: 5px;
box-shadow: 0 1px 5px #222;
opacity: .5;
cursor: pointer;
display: block;
color: #fff;
text-decoration: none;
}
.whois-result-tab:hover,
.whois-result-tab:focus {
opacity: .7;
}
.whois-result-tab-active {
opacity: 1 !important;
}
.whois-result-tab-header {
font-size: 1.3em;
line-height: 1.2em;
}
.whois-result-tab-server {
font-size: .9em;
line-height: 1.2em;
color: #888;
white-space: pre-wrap;
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
}

View file

@ -9,8 +9,6 @@ const assproc = require('./assets/assproc.js');
const rootDir = __dirname;
const assetsDir = path.join(rootDir, 'assets');
const assetsCSS = path.join(assetsDir, 'misuzu.css');
const assetsJS = path.join(assetsDir, 'misuzu.js');
const assetsInfo = path.join(assetsDir, 'current.json');
const pubDir = path.join(rootDir, 'public');
@ -58,30 +56,52 @@ postcssPlugins.push(require('autoprefixer')({
fs.mkdirSync(pubAssetsFull, { recursive: true });
(async () => {
const mszCssName = await assproc.process(assetsCSS, { 'prefix': '@', 'entry': 'main.css' })
.then(output => postcss(postcssPlugins).process(output, { from: assetsCSS }).then(output => {
const mszCssName = path.join(pubAssets, util.format(pubAssetCSSFormat, 'misuzu', utils.shortHash(output.css)));
fs.writeFileSync(path.join(pubDir, mszCssName), output.css);
return mszCssName;
}));
console.log('Building assets...');
const mszJsName = await assproc.process(assetsJS, { 'prefix': '#', 'entry': 'main.js' })
.then(output => swc.transform(output, {
filename: 'misuzu.js',
const dirs = fs.readdirSync(assetsDir);
const assets = {};
const _postcss = postcss(postcssPlugins);
for(const dir of dirs) {
const dirPath = path.join(assetsDir, dir);
if(!fs.statSync(dirPath).isDirectory())
continue;
const parts = dir.split('.', 2);
if(parts.length < 2)
continue;
console.log();
console.log(dir);
let filePath = '';
let fileBody = '';
if(parts[1] === 'js') {
fileBody = await assproc.process(dirPath, { 'prefix': '#', 'entry': 'main.js' });
fileBody = (await swc.transform(fileBody, {
filename: dir,
sourceMaps: false,
isModule: false,
minify: !isDebugBuild,
jsc: swcJscOptions,
}).then(async output => {
const mszJsName = path.join(pubAssets, util.format(pubAssetJSFormat, 'misuzu', utils.shortHash(output.code)));
fs.writeFileSync(path.join(pubDir, mszJsName), output.code);
return mszJsName;
}));
})).code;
filePath = path.join(pubAssets, util.format(pubAssetJSFormat, parts[0], utils.shortHash(fileBody)));
} else if(parts[1] === 'css') {
fileBody = await assproc.process(dirPath, { 'prefix': '@', 'entry': 'main.css' });
fileBody = (await _postcss.process(fileBody, { from: dir })).css;
filePath = path.join(pubAssets, util.format(pubAssetCSSFormat, parts[0], utils.shortHash(fileBody)));
}
fs.writeFileSync(assetsInfo, JSON.stringify({
mszjs: mszJsName,
mszcss: mszCssName,
}));
if(filePath !== '') {
assets[dir] = filePath;
fs.writeFileSync(path.join(pubDir, filePath), fileBody);
} else console.error(`Unknown type: ${parts[1]}`);
}
console.log('Writing assets info...');
fs.writeFileSync(assetsInfo, JSON.stringify(assets));
assproc.housekeep(pubAssetsFull);
})();

View file

@ -11,6 +11,7 @@ define('MKI_DIR_SRC', MKI_ROOT . '/src');
define('MKI_DIR_PUBLIC', MKI_ROOT . '/public');
define('MKI_DIR_CONFIG', MKI_ROOT . '/config');
define('MKI_DIR_TEMPLATES', MKI_ROOT . '/templates');
define('MKI_DIR_ASSETS', MKI_ROOT . '/assets');
require_once MKI_ROOT . '/vendor/autoload.php';

1157
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

33
src/AssetsInfo.php Normal file
View file

@ -0,0 +1,33 @@
<?php
namespace Makai;
final class AssetsInfo {
public function __construct(
private array $fileList
) {}
public function exists(string $name): bool {
return array_key_exists($name, $this->fileList);
}
public function get(string $name): string {
return $this->fileList[$name] ?? '';
}
public static function fromJson(string $body): self {
$body = json_decode($body, true);
return new static($body === false ? [] : $body);
}
public static function fromFile(string $path): self {
$body = file_get_contents($path);
if($body === false)
return new static([]);
return self::fromJson($body);
}
public static function fromCurrent(): self {
return self::fromFile(MKI_DIR_ASSETS . '/current.json');
}
}

View file

@ -60,6 +60,7 @@ final class MakaiContext {
);
$this->templating->addGlobal('globals', [
'siteInfo' => $this->siteInfo,
'assetsInfo' => AssetsInfo::fromCurrent(),
]);
}

View file

@ -3,6 +3,9 @@
{% set header_title = 'flash.moe / ascii table' %}
{% set header_minimal = true %}
{% set styles = styles|default([])|merge([ globals.assetsInfo.get('ascii.css') ]) %}
{% set scripts = scripts|default([])|merge([ globals.assetsInfo.get('ascii.js') ]) %}
{% set table = [
['Null character', 'NUL'],
['Start of heading', 'SOH'],
@ -179,79 +182,6 @@
{% endfor %}
</div>
</div>
<script type="text/javascript">
var chars = document.getElementsByClassName('ascii-char'),
search = document.getElementById('search');
function charsFilter(filter) {
if(!filter) {
for(var i = 0; i < chars.length; ++i)
chars[i].classList.remove('hidden');
return;
}
filter = filter.toLowerCase();
for(var i = 0; i < chars.length; ++i) {
var chr = chars[i],
code = (chr.dataset.keyCode || 0).toString().toLowerCase(),
print = (chr.dataset.keyPrint || "\0").toString().toLowerCase(),
desc = (chr.dataset.keyDesc || '').toString().toLowerCase(),
html = (chr.dataset.keyHtml || "\0").toString().toLowerCase(),
codeInt = parseInt(code),
isMatch = (filter === 'printable' && (codeInt > 31 && codeInt < 127))
|| (filter === 'control' && (codeInt < 32 || codeInt === 127))
|| code == filter || print == filter
|| html == filter || desc.indexOf(filter) >= 0;
chr.classList[isMatch ? 'remove' : 'add']('hidden');
}
};
window.addEventListener('scroll', function() {
var hidden = document.getElementsByClassName('js-hidden-on-scroll'),
invisible = document.getElementsByClassName('js-invisible-on-scroll'),
atTop = window.scrollY === 0;
for(var i = 0; i < hidden.length; ++i)
hidden[i].classList[atTop ? 'remove' : 'add']('hidden');
for(var i = 0; i < invisible.length; ++i)
invisible[i].classList[atTop ? 'remove' : 'add']('invisible');
});
search.addEventListener('keyup', function() {
location.hash = search.value.trim();
});
window.addEventListener('hashchange', function() {
charsFilter(decodeURIComponent((location.hash || '#').substring(1)));
});
if(location.hash.length > 0) {
search.value = location.hash.substring(1).trim();
charsFilter(search.value);
}
for(var i = 0; i < chars.length; ++i) {
chars[i].addEventListener('click', function(ev) {
var target = ev.target;
while(target !== null && typeof target.dataset.copy === 'undefined') {
target = target.parentNode || null;
if(target.classList.contains('char'))
break;
}
if(target === null || typeof target.dataset.copy === 'undefined')
return;
var doCopy = function() { navigator.clipboard.writeText(target.dataset.copy); };
if(typeof window.mozInnerScreenX !== 'undefined')
doCopy();
else
navigator.permissions.query({name: 'clipboard-write'}).then(function(res) {
if(res.state === 'granted' || res.state === 'prompt')
doCopy();
});
});
}
</script>
<script type="text/javascript" src="{{ globals.assetsInfo.get('ascii.js') }}"></script>
{% endblock %}

View file

@ -1 +1,67 @@
{% extends 'master.twig' %}
{% set master_title = (title is defined ? (title ~ ' // ') : '') ~ 'flash.moe' %}
{% set styles = styles|default([])|merge([
globals.assetsInfo.get('2021.css'),
'/fonts/electrolize/style.css',
globals.assetsInfo.get('common.css'),
]) %}
{% set scripts = scripts|default([])|merge([
globals.assetsInfo.get('2021.js'),
globals.assetsInfo.get('common.js'),
]) %}
{% set master_body_attrs = master_body_attrs|default([])|merge({
'class': html_classes({ 'index': header_is_index is defined, 'fullscreen-header': header_full is defined, 'now-playing': header_now_playing is defined, 'header-minimal': header_minimal is defined }),
}) %}
{% block master_head %}
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
{% endblock %}
{% block master_body %}
<div class="header">
<div class="header-background">
<img src="{{ random(globals.siteInfo.headerImages) }}" alt="">
</div>
<div class="header-foreground" {% if header_offset is defined and header_offset > 0 %}style="padding-bottom: {{ header_offset }}px"{% endif %}>
<a class="header-logo" href="/">
<div class="header-flash">{{ header_logo_flash|default('flash') }}</div>
<div class="header-wave">{{ header_logo_wave|default('wave') }}</div>
</a>
<div class="header-right">
<div class="header-now-playing header-now-playing-hidden">
<div class="header-now-playing-icon" title="Now listening to...">
<a href="/now-listening"><div class="fmi fmi-music"></div></a>
</div>
<div class="header-now-playing-cover">
<img src="//now.flash.moe/resources/no-cover.png" alt="">
</div>
<div class="header-now-playing-details">
<div class="header-now-playing-title"><a href="#" target="_blank" rel="noopener"></a></div>
<div class="header-now-playing-artist"><a href="#" target="_blank" rel="noopener"></a></div>
</div>
</div>
<div class="header-menu">
{% for link in globals.siteInfo.headerNavigation %}
<a href="{{ link.link }}">{{ link.title }}</a>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="container">
{% block container %}
{% endblock %}
</div>
<div class="footer">
<div class="footer-text">&copy; flashwave {{ footer_copy_start|default('2010') }}-{{ footer_copy_end|default(('now'|date('Y'))) }} - {{ random(globals.siteInfo.footerQuotes) }}</div>
</div>
{% if footer_onload is defined %}
<script type="text/javascript">
window.fm = { onload: {{ footer_onload|json_encode|raw }} };
</script>
{% endif %}
{% endblock %}

View file

@ -1,56 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>{% if title is defined %}{{ title }} // {% endif %}flash.moe</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link href="/assets/2021.css" type="text/css" rel="stylesheet">
<link href="/assets/sprite.css" type="text/css" rel="stylesheet">
<link href="/fonts/electrolize/style.css" type="text/css" rel="stylesheet">
</head>
<body class="{{ html_classes({ 'index': header_is_index is defined, 'fullscreen-header': header_full is defined, 'now-playing': header_now_playing is defined, 'header-minimal': header_minimal is defined }) }}">
<div class="header">
<div class="header-background">
<img src="{{ random(globals.siteInfo.headerImages) }}" alt="">
</div>
<div class="header-foreground" {% if header_offset is defined and header_offset > 0 %}style="padding-bottom: {{ header_offset }}px"{% endif %}>
<a class="header-logo" href="/">
<div class="header-flash">{{ header_logo_flash|default('flash') }}</div>
<div class="header-wave">{{ header_logo_wave|default('wave') }}</div>
</a>
<div class="header-right">
<div class="header-now-playing header-now-playing-hidden">
<div class="header-now-playing-icon" title="Now listening to...">
<a href="/now-listening"><div class="fmi fmi-music"></div></a>
</div>
<div class="header-now-playing-cover">
<img src="//now.flash.moe/resources/no-cover.png" alt="">
</div>
<div class="header-now-playing-details">
<div class="header-now-playing-title"><a href="#" target="_blank" rel="noopener"></a></div>
<div class="header-now-playing-artist"><a href="#" target="_blank" rel="noopener"></a></div>
</div>
</div>
<div class="header-menu">
{% for link in globals.siteInfo.headerNavigation %}
<a href="{{ link.link }}">{{ link.title }}</a>
<meta charset="{{ master_charset|default('utf-8') }}">
{% if master_title is defined and master_title is not empty %}<title>{{ master_title }}</title>{% endif %}
{% block master_head %}{% endblock %}
{% if styles is defined and styles is iterable and styles is not empty %}
{% for style in styles|reverse %}
<link href="{{ style }}" type="text/css" rel="stylesheet">
{% endfor %}
{% endif %}
</head>
<body{% if master_body_attrs is defined and master_body_attrs is not empty %}{% for name, value in master_body_attrs %}{% if value is not empty %} {{ name }}="{{ value }}"{% endif %}{% endfor %}{% endif %}>
{% block master_body %}{% endblock %}
{% if scripts is defined and scripts is iterable and scripts is not empty %}
{% for script in scripts|reverse %}
<script src="{{ script }}" charset="utf-8" type="text/javascript"></script>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="container">
{% block container %}
{% endblock %}
</div>
<div class="footer">
<div class="footer-text">&copy; flashwave {{ footer_copy_start|default('2010') }}-{{ footer_copy_end|default(('now'|date('Y'))) }} - {{ random(globals.siteInfo.footerQuotes) }}</div>
</div>
{% if footer_onload is defined %}
<script type="text/javascript">
window.fm = { onload: {{ footer_onload|json_encode|raw }} };
</script>
{% endif %}
<script src="/assets/2021.js" charset="utf-8" type="text/javascript"></script>
</body>
</html>

View file

@ -6,6 +6,9 @@
{% set header_minimal = true %}
{% set footer_copy_start = '2013' %}
{% set styles = styles|default([])|merge([ globals.assetsInfo.get('whois.css') ]) %}
{% set scripts = scripts|default([])|merge([ globals.assetsInfo.get('whois.js') ]) %}
{% block container %}
<div class="whois-container">
<form class="whois-lookup-form" method="get" action="">
@ -20,6 +23,4 @@
</div>
</div>
</div>
<script type="text/javascript" src="/assets/2021whois.js"></script>
{% endblock %}