Compare commits
2 commits
84261c9537
...
8551c37e7a
| Author | SHA1 | Date | |
|---|---|---|---|
| 8551c37e7a | |||
| 441056cabc |
14 changed files with 294 additions and 236 deletions
|
|
@ -33,6 +33,8 @@ COPY --from=install /temp/prod/node_modules node_modules
|
||||||
COPY --from=prerelease /usr/src/app/dist ./dist
|
COPY --from=prerelease /usr/src/app/dist ./dist
|
||||||
COPY --from=prerelease /usr/src/app/package.json ./
|
COPY --from=prerelease /usr/src/app/package.json ./
|
||||||
|
|
||||||
|
ENV HOST=0.0.0.0
|
||||||
|
|
||||||
USER node
|
USER node
|
||||||
EXPOSE 4321
|
EXPOSE 4321
|
||||||
ENTRYPOINT ["node", "./dist/server/entry.mjs"]
|
ENTRYPOINT ["node", "./dist/server/entry.mjs"]
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,12 @@ export default defineConfig({
|
||||||
site: "https://badblocks.dev",
|
site: "https://badblocks.dev",
|
||||||
trailingSlash: "never",
|
trailingSlash: "never",
|
||||||
// bun adapter is not official, also a little wonky, so use node adapter for now
|
// bun adapter is not official, also a little wonky, so use node adapter for now
|
||||||
adapter: node({
|
|
||||||
mode: "standalone",
|
|
||||||
}),
|
|
||||||
// adapter: bun(),
|
// adapter: bun(),
|
||||||
// output: "static",
|
// output: "static",
|
||||||
|
adapter: node({
|
||||||
|
mode: "standalone",
|
||||||
|
staticHeaders: true,
|
||||||
|
}),
|
||||||
compressHTML: false,
|
compressHTML: false,
|
||||||
devToolbar: { enabled: false },
|
devToolbar: { enabled: false },
|
||||||
prefetch: {
|
prefetch: {
|
||||||
|
|
@ -29,7 +30,6 @@ export default defineConfig({
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
host: true,
|
|
||||||
port: 4321,
|
port: 4321,
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
|
|
@ -57,7 +57,4 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
integrations: [alpinejs(), sitemap()],
|
integrations: [alpinejs(), sitemap()],
|
||||||
experimental: {
|
|
||||||
chromeDevtoolsWorkspace: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
12
compose.yaml
12
compose.yaml
|
|
@ -6,12 +6,12 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./db:/db
|
- ./db:/db
|
||||||
environment:
|
environment:
|
||||||
ANDROID_SMS_GATEWAY_IP: ${ANDROID_SMS_GATEWAY_IP:-192.168.0.1}
|
ANDROID_SMS_GATEWAY_IP: ${ANDROID_SMS_GATEWAY_IP:?ANDROID_SMS_GATEWAY_IP is required}
|
||||||
ANDROID_SMS_GATEWAY_URL: ${ANDROID_SMS_GATEWAY_URL:-http://192.168.0.1:8080}
|
ANDROID_SMS_GATEWAY_URL: ${ANDROID_SMS_GATEWAY_URL:? ANDROID_SMS_GATEWAY_URL is required}
|
||||||
ANDROID_SMS_GATEWAY_LOGIN: ${ANDROID_SMS_GATEWAY_LOGIN:-sms}
|
ANDROID_SMS_GATEWAY_LOGIN: ${ANDROID_SMS_GATEWAY_LOGIN:? ANDROID_SMS_GATEWAY_LOGIN is required}
|
||||||
ANDROID_SMS_GATEWAY_PASSWORD: ${ANDROID_SMS_GATEWAY_PASSWORD:-super-secret-password}
|
ANDROID_SMS_GATEWAY_PASSWORD: ${ANDROID_SMS_GATEWAY_PASSWORD:?ANDROID_SMS_GATEWAY_PASSWORD is required}
|
||||||
ANDROID_SMS_GATEWAY_RECIPIENT_PHONE: ${ANDROID_SMS_GATEWAY_RECIPIENT_PHONE:-555-555-1234}
|
ANDROID_SMS_GATEWAY_RECIPIENT_PHONE: ${ANDROID_SMS_GATEWAY_RECIPIENT_PHONE:? ANDROID_SMS_GATEWAY_RECIPIENT_PHONE is required}
|
||||||
OTP_SUPER_SECRET_SALT: ${OTP_SUPER_SECRET_SALT:-super-secret-salt}
|
OTP_SUPER_SECRET_SALT: ${OTP_SUPER_SECRET_SALT:?OTP_SUPER_SECRET_SALT is required}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test:
|
test:
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
"iconify-icon": "^3.0.2",
|
"iconify-icon": "^3.0.2",
|
||||||
"ofetch": "^1.5.1",
|
"ofetch": "^1.5.1",
|
||||||
"otplib": "12.0.1",
|
"otplib": "12.0.1",
|
||||||
|
"thirty-two": "^1.0.2",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
"validator": "^13.15.35"
|
"validator": "^13.15.35"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -42,12 +42,12 @@ body {
|
||||||
var(--color-accent-transparent),
|
var(--color-accent-transparent),
|
||||||
black 120%
|
black 120%
|
||||||
);
|
);
|
||||||
|
background-attachment: fixed;
|
||||||
color: var(--color-fg);
|
color: var(--color-fg);
|
||||||
column-gap: var(--gutter-large);
|
column-gap: var(--gutter-large);
|
||||||
display: grid;
|
display: grid;
|
||||||
font-size: var(--pt-pica);
|
font-size: var(--pt-pica);
|
||||||
grid-template-rows: auto 1fr auto;
|
grid-template-rows: auto 1fr auto;
|
||||||
height: 100dvb;
|
|
||||||
left: 0;
|
left: 0;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
padding-inline: var(--page-padding-inline);
|
padding-inline: var(--page-padding-inline);
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,31 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<!--prettier-ignore-->
|
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="preload" href="/unscii-16.woff" as="font" crossorigin="anonymous" />
|
<link
|
||||||
|
rel="preload"
|
||||||
|
href="/unscii-16.woff"
|
||||||
|
as="font"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
<link rel="preload" href="reset.css" as="style" />
|
<link rel="preload" href="reset.css" as="style" />
|
||||||
<link rel="preload" href="theme.css" as="style" />
|
<link rel="preload" href="theme.css" as="style" />
|
||||||
<link rel="stylesheet" type="text/css" href="/style.css" />
|
<link rel="stylesheet" type="text/css" href="/style.css" />
|
||||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' width='100px' height='100px'><rect x='0' y='0' width='100' height='100' rx='15' ry='15' style='fill: rgb(0,0,0);'/><foreignObject width='100' height='100'><div xmlns='http://www.w3.org/1999/xhtml' style='width:100px;height:100px;line-height:100px;text-align:center;vertical-align:middle;color:transparent;text-shadow: 0 0 rgb(0 255 0);font-size:80px;'>👾</div></foreignObject></svg>"/>
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/svg+xml"
|
||||||
|
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' width='100px' height='100px'><rect x='0' y='0' width='100' height='100' rx='15' ry='15' style='fill: rgb(0,0,0);'/><foreignObject width='100' height='100'><div xmlns='http://www.w3.org/1999/xhtml' style='width:100px;height:100px;line-height:100px;text-align:center;vertical-align:middle;color:transparent;text-shadow: 0 0 rgb(0 255 0);font-size:80px;'>👾</div></foreignObject></svg>"
|
||||||
|
/>
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<meta name="darkreader-lock" />
|
<meta name="darkreader-lock" />
|
||||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||||
<script is:inline src="/htmz.js"></script>
|
<script is:inline src="/htmz.js"></script>
|
||||||
<script is:inline async src="/goat.js" data-goatcounter="https://badblocks.goatcounter.com/count"></script>
|
<script
|
||||||
|
is:inline
|
||||||
|
async
|
||||||
|
src="/goat.js"
|
||||||
|
data-goatcounter="https://badblocks.goatcounter.com/count"></script>
|
||||||
<slot name="head" />
|
<slot name="head" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -34,9 +46,16 @@
|
||||||
<footer>
|
<footer>
|
||||||
<p>
|
<p>
|
||||||
<a href="/license">
|
<a href="/license">
|
||||||
<img src="/mit.svg" title="MIT Licensed" alt="MIT License Logo" width="24" height="24" role="img">
|
<img
|
||||||
|
src="/mit.svg"
|
||||||
|
title="MIT Licensed"
|
||||||
|
alt="MIT License Logo"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
role="img"
|
||||||
|
/>
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br />
|
||||||
Made from scratch with BAHz: Bun, Astro, and Htmz!
|
Made from scratch with BAHz: Bun, Astro, and Htmz!
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { authenticator } from "otplib";
|
import { authenticator } from "otplib";
|
||||||
import { createHash } from "crypto";
|
import { createHmac } from "crypto";
|
||||||
|
import base32 from "thirty-two";
|
||||||
|
|
||||||
const submissionTimestamps = new Map<string, number[]>();
|
const submissionTimestamps = new Map<string, number[]>();
|
||||||
const otpRequestTimestamps = new Map<string, number[]>();
|
const otpRequestTimestamps = new Map<string, number[]>();
|
||||||
|
|
@ -52,9 +53,9 @@ function getUserSecret(phoneNumber: string, salt: string): string {
|
||||||
"Phone number and salt are required to generate a user secret.",
|
"Phone number and salt are required to generate a user secret.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return createHash("sha256")
|
|
||||||
.update(phoneNumber + salt)
|
const digest = createHmac("sha256", salt).update(phoneNumber).digest("hex");
|
||||||
.digest("hex");
|
return base32.encode(digest).toString().replace(/=/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizePhone(phone: string) {
|
export function normalizePhone(phone: string) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
import Layout from "@layouts/BaseLayout.astro";
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout>
|
|
||||||
<title slot="head">AI Policy</title>
|
|
||||||
<Fragment slot="main"> </Fragment>
|
|
||||||
</Layout>
|
|
||||||
|
|
@ -157,7 +157,12 @@ const msgValue = pickValue("msg") || (await Astro.session?.get("msg"));
|
||||||
{result?.error.message}
|
{result?.error.message}
|
||||||
Please correct any errors and try again.
|
Please correct any errors and try again.
|
||||||
</p>
|
</p>
|
||||||
)) || <p>Use this form to shoot me a quick text!</p>}
|
)) || (
|
||||||
|
<p>
|
||||||
|
Inquiries, opportunities, or comments? Shoot me a quick text
|
||||||
|
here!
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<fieldset id="send_otp_fields" disabled={nextAction != "send_otp"}>
|
<fieldset id="send_otp_fields" disabled={nextAction != "send_otp"}>
|
||||||
<label for="name">
|
<label for="name">
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import type { APIRoute } from "astro";
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
export const GET: APIRoute = async () => {
|
export const GET: APIRoute = async () => {
|
||||||
|
// flesh out later if needed
|
||||||
try {
|
try {
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,242 @@ import Layout from "@layouts/BaseLayout.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout>
|
<Layout>
|
||||||
<title slot="head">Home</title>
|
<title slot="head">Parallax Demo</title>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--scroll-multiplier: 5;
|
||||||
|
--theme: winternight;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-theme-winternight {
|
||||||
|
--layer-0-speed: 6250s;
|
||||||
|
--layer-1-speed: 1250s;
|
||||||
|
--layer-2-speed: 500s;
|
||||||
|
--layer-3-speed: 250s;
|
||||||
|
--layer-4-speed: 80s;
|
||||||
|
--layer-0-url: url("/parallax/winternight/0-sky.png");
|
||||||
|
--layer-1-url: url("/parallax/winternight/1-backmountain.png");
|
||||||
|
--layer-2-url: url("/parallax/winternight/2-midmountain.png");
|
||||||
|
--layer-3-url: url("/parallax/winternight/3-midforest.png");
|
||||||
|
--layer-4-url: url("/parallax/winternight/4-frontfloor.png");
|
||||||
|
--parallax-width: calc(3800px * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-theme-sunnyvale-forest {
|
||||||
|
--layer-0-speed: 2000s;
|
||||||
|
--layer-1-speed: 400s;
|
||||||
|
--layer-2-speed: 50s;
|
||||||
|
--layer-0-url: url("/parallax/sunnyvale-forest/0-clouds.png");
|
||||||
|
--layer-1-url: url("/parallax/sunnyvale-forest/1-mountains.png");
|
||||||
|
--layer-2-url: url("/parallax/sunnyvale-forest/2-trees.png");
|
||||||
|
--parallax-width: calc(160px * 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-theme-city-destroyed {
|
||||||
|
--layer-0-speed: 1000s;
|
||||||
|
--layer-1-speed: 275s;
|
||||||
|
--layer-2-speed: 250s;
|
||||||
|
--layer-3-speed: 250s;
|
||||||
|
--layer-4-speed: 250s;
|
||||||
|
--layer-5-speed: 100s;
|
||||||
|
--layer-0-url: url("/parallax/city-destroyed/0-sky.png");
|
||||||
|
--layer-1-url: url("/parallax/city-destroyed/1-buildingssmoke.png");
|
||||||
|
--layer-2-url: url("/parallax/city-destroyed/2-water.png");
|
||||||
|
--layer-3-url: url("/parallax/city-destroyed/3-buildings.png");
|
||||||
|
--layer-4-url: url("/parallax/city-destroyed/4-buildingreflection.png");
|
||||||
|
--layer-5-url: url("/parallax/city-destroyed/5-frontsmoke.png");
|
||||||
|
--parallax-width: calc(3800px * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-theme-city-destroyed .layer.layer-1,
|
||||||
|
.parallax-theme-city-destroyed .layer.layer-3,
|
||||||
|
.parallax-theme-city-destroyed .layer.layer-4 {
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-theme-city-destroyed .layer.layer-4 {
|
||||||
|
background-position-y: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parallax-container {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: var(--parallax-width);
|
||||||
|
background-repeat: round;
|
||||||
|
background-position: bottom;
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-0 {
|
||||||
|
background-image: var(--layer-0-url);
|
||||||
|
z-index: 1;
|
||||||
|
animation: scroll calc(var(--scroll-multiplier) * var(--layer-0-speed))
|
||||||
|
linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-1 {
|
||||||
|
background-image: var(--layer-1-url);
|
||||||
|
z-index: 2;
|
||||||
|
animation: scroll calc(var(--scroll-multiplier) * var(--layer-1-speed))
|
||||||
|
linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-2 {
|
||||||
|
background-image: var(--layer-2-url);
|
||||||
|
z-index: 3;
|
||||||
|
animation: scroll calc(var(--scroll-multiplier) * var(--layer-2-speed))
|
||||||
|
linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-3 {
|
||||||
|
background-image: var(--layer-3-url);
|
||||||
|
z-index: 4;
|
||||||
|
animation: scroll calc(var(--scroll-multiplier) * var(--layer-3-speed))
|
||||||
|
linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-4 {
|
||||||
|
background-image: var(--layer-4-url);
|
||||||
|
z-index: 5;
|
||||||
|
animation: scroll calc(var(--scroll-multiplier) * var(--layer-4-speed))
|
||||||
|
linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layer-5 {
|
||||||
|
background-image: var(--layer-5-url);
|
||||||
|
z-index: 6;
|
||||||
|
animation: scroll calc(var(--scroll-multiplier) * var(--layer-5-speed))
|
||||||
|
linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scroll {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-monitor {
|
||||||
|
margin: 10px auto 0px auto;
|
||||||
|
width: 330px;
|
||||||
|
height: 230px;
|
||||||
|
border: 4px solid #34495e;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-audio {
|
||||||
|
border: 2px solid #34495e;
|
||||||
|
width: 10px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 6px auto 0px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-screen {
|
||||||
|
margin: 5px auto 0px auto;
|
||||||
|
border: 3px solid #34495e;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 305px;
|
||||||
|
height: 195px;
|
||||||
|
background-color: black;
|
||||||
|
object-fit: contain;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-screen-text {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-keyboard {
|
||||||
|
width: 360px;
|
||||||
|
height: 20px;
|
||||||
|
border: 4px solid #34495e;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: -4px auto 2px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-keyboard-detail {
|
||||||
|
border: 1px solid #34495e;
|
||||||
|
width: 50px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin: 0px auto 0px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-keyboard-base {
|
||||||
|
width: 360px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #34495e;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: -2px auto 4px auto;
|
||||||
|
clip-path: polygon(10% 0, 90% 0, 100% 100%, 0 100%);
|
||||||
|
}
|
||||||
|
.sided {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.sided > div {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<Fragment slot="main">
|
<Fragment slot="main">
|
||||||
<article id="hero">
|
<article
|
||||||
<h2>Hi, I'm badblocks!</h2>
|
id="hero"
|
||||||
<p>I ♥ building websites and making things!</p>
|
x-data="{
|
||||||
|
themes: [
|
||||||
|
{ value: 'winternight', label: 'Winternight' },
|
||||||
|
{ value: 'sunnyvale-forest', label: 'SunnyVale' },
|
||||||
|
{ value: 'city-destroyed', label: 'Apocalypse' },
|
||||||
|
],
|
||||||
|
index: 0,
|
||||||
|
get theme() { return this.themes[this.index].value },
|
||||||
|
next() { this.index = (this.index + 1) % this.themes.length },
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="sided">
|
||||||
|
<div>
|
||||||
|
<h2>Hi, I'm badblocks!</h2>
|
||||||
|
<p>I ♥ building websites and making things!</p>
|
||||||
|
</div><div class="desktop">
|
||||||
|
<div class="desktop-monitor">
|
||||||
|
<div class="desktop-audio"></div>
|
||||||
|
<div class="desktop-screen" @click="next()">
|
||||||
|
<div
|
||||||
|
class="parallax-container"
|
||||||
|
:class="'parallax-theme-' + theme"
|
||||||
|
>
|
||||||
|
<div class="layer layer-0"></div>
|
||||||
|
<div class="layer layer-1"></div>
|
||||||
|
<div class="layer layer-2"></div>
|
||||||
|
<div class="layer layer-3"></div>
|
||||||
|
<div class="layer layer-4"></div>
|
||||||
|
<div class="layer layer-5"></div>
|
||||||
|
</div>
|
||||||
|
<div class="desktop-screen-text" x-text="themes[index].label">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="desktop-keyboard-base"></div>
|
||||||
|
<div class="desktop-keyboard">
|
||||||
|
<div class="desktop-keyboard-detail"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
||||||
|
|
@ -1,152 +0,0 @@
|
||||||
---
|
|
||||||
import Layout from "@layouts/BaseLayout.astro";
|
|
||||||
---
|
|
||||||
|
|
||||||
<Layout>
|
|
||||||
<title slot="head">Parallax Demo</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--scroll-multiplier: 5;
|
|
||||||
--theme: winternight;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-theme-winternight {
|
|
||||||
--layer-0-speed: 6250s;
|
|
||||||
--layer-1-speed: 1250s;
|
|
||||||
--layer-2-speed: 500s;
|
|
||||||
--layer-3-speed: 250s;
|
|
||||||
--layer-4-speed: 80s;
|
|
||||||
--layer-0-url: url("/parallax/winternight/0-sky.png");
|
|
||||||
--layer-1-url: url("/parallax/winternight/1-backmountain.png");
|
|
||||||
--layer-2-url: url("/parallax/winternight/2-midmountain.png");
|
|
||||||
--layer-3-url: url("/parallax/winternight/3-midforest.png");
|
|
||||||
--layer-4-url: url("/parallax/winternight/4-frontfloor.png");
|
|
||||||
--parallax-width: calc(3800px * 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-theme-sunnyvale-forest {
|
|
||||||
--layer-0-speed: 2000s;
|
|
||||||
--layer-1-speed: 400s;
|
|
||||||
--layer-2-speed: 50s;
|
|
||||||
--layer-0-url: url("/parallax/sunnyvale-forest/0-clouds.png");
|
|
||||||
--layer-1-url: url("/parallax/sunnyvale-forest/1-mountains.png");
|
|
||||||
--layer-2-url: url("/parallax/sunnyvale-forest/2-trees.png");
|
|
||||||
--parallax-width: calc(160px * 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-theme-city-destroyed {
|
|
||||||
--layer-0-speed: 1000s;
|
|
||||||
--layer-1-speed: 275s;
|
|
||||||
--layer-2-speed: 250s;
|
|
||||||
--layer-3-speed: 250s;
|
|
||||||
--layer-4-speed: 250s;
|
|
||||||
--layer-5-speed: 100s;
|
|
||||||
--layer-0-url: url("/parallax/city-destroyed/0-sky.png");
|
|
||||||
--layer-1-url: url("/parallax/city-destroyed/1-buildingssmoke.png");
|
|
||||||
--layer-2-url: url("/parallax/city-destroyed/2-water.png");
|
|
||||||
--layer-3-url: url("/parallax/city-destroyed/3-buildings.png");
|
|
||||||
--layer-4-url: url("/parallax/city-destroyed/4-buildingreflection.png");
|
|
||||||
--layer-5-url: url("/parallax/city-destroyed/5-frontsmoke.png");
|
|
||||||
--parallax-width: calc(3800px * 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-theme-city-destroyed .layer.layer-1,
|
|
||||||
.parallax-theme-city-destroyed .layer.layer-3,
|
|
||||||
.parallax-theme-city-destroyed .layer.layer-4 {
|
|
||||||
background-repeat: repeat-x;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-theme-city-destroyed .layer.layer-4 {
|
|
||||||
background-position-y: 16rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parallax-container {
|
|
||||||
position: relative;
|
|
||||||
height: 30rem;
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: var(--parallax-width);
|
|
||||||
background-repeat: round;
|
|
||||||
background-position: bottom;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-0 {
|
|
||||||
background-image: var(--layer-0-url);
|
|
||||||
z-index: 1;
|
|
||||||
animation: scroll calc(var(--scroll-multiplier) * var(--layer-0-speed))
|
|
||||||
linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-1 {
|
|
||||||
background-image: var(--layer-1-url);
|
|
||||||
z-index: 2;
|
|
||||||
animation: scroll calc(var(--scroll-multiplier) * var(--layer-1-speed))
|
|
||||||
linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-2 {
|
|
||||||
background-image: var(--layer-2-url);
|
|
||||||
z-index: 3;
|
|
||||||
animation: scroll calc(var(--scroll-multiplier) * var(--layer-2-speed))
|
|
||||||
linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-3 {
|
|
||||||
background-image: var(--layer-3-url);
|
|
||||||
z-index: 4;
|
|
||||||
animation: scroll calc(var(--scroll-multiplier) * var(--layer-3-speed))
|
|
||||||
linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-4 {
|
|
||||||
background-image: var(--layer-4-url);
|
|
||||||
z-index: 5;
|
|
||||||
animation: scroll calc(var(--scroll-multiplier) * var(--layer-4-speed))
|
|
||||||
linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.layer-5 {
|
|
||||||
background-image: var(--layer-5-url);
|
|
||||||
z-index: 6;
|
|
||||||
animation: scroll calc(var(--scroll-multiplier) * var(--layer-5-speed))
|
|
||||||
linear infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes scroll {
|
|
||||||
0% {
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<Fragment slot="main">
|
|
||||||
<article id="hero" x-data="{ theme: 'winternight'}">
|
|
||||||
<div class="parallax-container" :class="'parallax-theme-' + theme">
|
|
||||||
<div class="layer layer-0"></div>
|
|
||||||
<div class="layer layer-1"></div>
|
|
||||||
<div class="layer layer-2"></div>
|
|
||||||
<div class="layer layer-3"></div>
|
|
||||||
<div class="layer layer-4"></div>
|
|
||||||
<div class="layer layer-5"></div>
|
|
||||||
</div>
|
|
||||||
<h2>Parallax Demo</h2>
|
|
||||||
<p>Pardon the dust!</p>
|
|
||||||
<select id="theme" x-model="theme">
|
|
||||||
<option value="winternight">Winternight</option>
|
|
||||||
<option value="sunnyvale-forest">SunnyVale</option>
|
|
||||||
<option value="city-destroyed">Apocalypse</option>
|
|
||||||
</select>
|
|
||||||
</article>
|
|
||||||
</Fragment>
|
|
||||||
</Layout>
|
|
||||||
8
src/thirty-two.d.ts
vendored
Normal file
8
src/thirty-two.d.ts
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
declare module "thirty-two" {
|
||||||
|
interface Base32 {
|
||||||
|
encode(input: string | Buffer): Buffer;
|
||||||
|
decode(input: string | Buffer): Buffer;
|
||||||
|
}
|
||||||
|
const base32: Base32;
|
||||||
|
export = base32;
|
||||||
|
}
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cd $(dirname $(dirname $(realpath $0)))
|
|
||||||
|
|
||||||
# Path to the original .env file
|
|
||||||
ENV_FILE=".env"
|
|
||||||
# Path to the new .env.example file
|
|
||||||
EXAMPLE_FILE=".env.example"
|
|
||||||
|
|
||||||
# Check if the .env file exists
|
|
||||||
if [ ! -f "$ENV_FILE" ]; then
|
|
||||||
echo "The file $ENV_FILE does not exist."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create or empty the .env.example file
|
|
||||||
> "$EXAMPLE_FILE"
|
|
||||||
|
|
||||||
SKIP_NEXT=false
|
|
||||||
|
|
||||||
# Read each line in .env
|
|
||||||
while IFS= read -r line; do
|
|
||||||
# Skip the current line if the previous line is part of a multiline/quoted string
|
|
||||||
if [[ $SKIP_NEXT == true ]]; then
|
|
||||||
if [[ $line == *'"'* ]]; then
|
|
||||||
SKIP_NEXT=false
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
# Copy comments and empty lines verbatim
|
|
||||||
elif [[ $line == \#* ]] || [[ -z $line ]]; then
|
|
||||||
echo "$line" >> "$EXAMPLE_FILE"
|
|
||||||
continue
|
|
||||||
# Check if the line is a multiline/quoted string
|
|
||||||
elif [[ $line == *'="'* ]]; then
|
|
||||||
if [[ $line != *'"' ]]; then
|
|
||||||
SKIP_NEXT=true
|
|
||||||
fi
|
|
||||||
LINE=${line%%=*}
|
|
||||||
echo "$LINE=\"\${$LINE}\"" >> "$EXAMPLE_FILE"
|
|
||||||
# For all other lines, copy only the key (everything before the '=') if present
|
|
||||||
elif [[ $line == *'='* ]]; then
|
|
||||||
LINE=${line%%=*}
|
|
||||||
echo "$LINE=\${$LINE}" >> "$EXAMPLE_FILE"
|
|
||||||
fi
|
|
||||||
done < "$ENV_FILE"
|
|
||||||
|
|
||||||
echo ".env.example file created successfully."
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue