initial
This commit is contained in:
parent
d73b9b27f7
commit
8bc6e2496b
3 changed files with 135 additions and 772 deletions
File diff suppressed because one or more lines are too long
494
public/script.js
494
public/script.js
|
@ -1,421 +1,111 @@
|
|||
// <CRYPTO_DONATION>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var donateButton = document.getElementById("donateButton");
|
||||
var card = document.getElementById("card");
|
||||
// braille
|
||||
|
||||
donateButton.addEventListener("click", function (event) {
|
||||
event.stopPropagation();
|
||||
if (card.classList.contains("card-out")) {
|
||||
card.classList.remove("card-out");
|
||||
card.classList.add("card-in");
|
||||
} else {
|
||||
card.classList.remove("card-in");
|
||||
card.classList.add("card-out");
|
||||
}
|
||||
});
|
||||
const enc = (x) =>
|
||||
((x & 0x08) << 3) | ((x & 0x70) >> 1) | (x & 0x87) | 0x2800;
|
||||
const row = (x) => String.fromCharCode(...Array.from(x, enc));
|
||||
|
||||
window.addEventListener("click", function (event) {
|
||||
if (event.target === card || card.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
const create = (width, height) =>
|
||||
Array.from(Array(height >> 2), () => new Uint8Array(width >> 1));
|
||||
|
||||
if (card.classList.contains("card-in")) {
|
||||
card.classList.remove("card-in");
|
||||
card.classList.add("card-out");
|
||||
}
|
||||
});
|
||||
const set = (table, x, y) =>
|
||||
(table[y >> 2][x >> 1] |= 1 << ((y & 3) | ((x & 1) << 2)));
|
||||
|
||||
var cryptoWallets = [
|
||||
{
|
||||
symbol: "XMR",
|
||||
name: "Monero",
|
||||
address:
|
||||
"49r2aeun8DtV5VqZpZSwRpS83WfUWEaLt4NG8HJwwVkbiT1vSsXTXrPFKkKTdc6MPX9iezbTidNPvhGZKCnM1338TfK6Hgi"
|
||||
},
|
||||
{
|
||||
symbol: "LTC",
|
||||
name: "Litecoin",
|
||||
address: "LRAm7h5XENknfYEpbdVsvyGY8D6MiXGTDV"
|
||||
},
|
||||
{
|
||||
symbol: "BTC",
|
||||
name: "Bitcoin",
|
||||
address: "bc1qkv97ajh7f0a72l9rsjd3fmmly5q5uywr06q3x0"
|
||||
}
|
||||
];
|
||||
const render = (table) => table.map(row).join("\n");
|
||||
|
||||
var walletsContainer = document.getElementById("wallets");
|
||||
var qrImage = document.getElementById("qrImage");
|
||||
var donateTitle = document.getElementById("donateTitle");
|
||||
var donateWarn = document.getElementById("donateWarn");
|
||||
var walletAddress = document.getElementById("walletAddress");
|
||||
var copyButton = document.getElementById("copyButton");
|
||||
// util
|
||||
|
||||
function selectWallet(symbol) {
|
||||
var wallet = cryptoWallets.find(function (w) {
|
||||
return w.symbol === symbol;
|
||||
});
|
||||
if (!wallet) return;
|
||||
const frame = () => new Promise((resolve) => requestAnimationFrame(resolve));
|
||||
|
||||
var buttons = Array.from(walletsContainer.children);
|
||||
buttons.forEach(function (button) {
|
||||
button.classList.remove("active");
|
||||
if (button.textContent === symbol) {
|
||||
button.classList.add("active");
|
||||
}
|
||||
});
|
||||
const element = (name, options) =>
|
||||
Object.assign(document.createElement(name), options);
|
||||
|
||||
qrImage.src =
|
||||
"https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=" +
|
||||
wallet.address;
|
||||
donateTitle.textContent = "Donate " + wallet.name;
|
||||
donateWarn.textContent =
|
||||
"Send only " +
|
||||
wallet.name +
|
||||
" (" +
|
||||
wallet.symbol +
|
||||
") to this deposit address. Sending any other coin or token to this address may result in the loss of your donation. Thanks!";
|
||||
walletAddress.value = wallet.address;
|
||||
copyButton.textContent = "✚ Copy";
|
||||
}
|
||||
// bayer
|
||||
|
||||
function copyText() {
|
||||
var input = document.createElement("input");
|
||||
document.body.appendChild(input);
|
||||
input.value = walletAddress.value;
|
||||
input.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(input);
|
||||
copyButton.textContent = "✔ Copied";
|
||||
}
|
||||
|
||||
cryptoWallets.forEach(function (wallet) {
|
||||
var button = document.createElement("button");
|
||||
button.textContent = wallet.symbol;
|
||||
button.addEventListener("click", function () {
|
||||
selectWallet(wallet.symbol);
|
||||
});
|
||||
walletsContainer.appendChild(button);
|
||||
});
|
||||
|
||||
copyButton.addEventListener("click", copyText);
|
||||
|
||||
selectWallet(cryptoWallets[0].symbol);
|
||||
|
||||
// </CRYPTO_DONATION>
|
||||
|
||||
let globalUniforms = {
|
||||
time: { value: 0 }
|
||||
const bayer = (order, x, y) => {
|
||||
let z = 0;
|
||||
for (let i = order; i--; x >>= 1, y >>= 1)
|
||||
z = ((((x & 1) ^ (y & 1)) | (z << 1)) << 1) | (y & 1);
|
||||
return z;
|
||||
};
|
||||
|
||||
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
|
||||
import { OrbitControls } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";
|
||||
import {
|
||||
CSS2DRenderer,
|
||||
CSS2DObject
|
||||
} from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/renderers/CSS2DRenderer.js";
|
||||
|
||||
let scene = new THREE.Scene();
|
||||
let camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 2000);
|
||||
camera.position.set(-5, 4, -0.8).setLength(14);
|
||||
let renderer = new THREE.WebGLRenderer({
|
||||
antialias: true
|
||||
});
|
||||
renderer.setSize(innerWidth, innerHeight);
|
||||
renderer.setClearColor(0x241917);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
let labelRenderer = new CSS2DRenderer();
|
||||
labelRenderer.setSize(window.innerWidth, window.innerHeight);
|
||||
labelRenderer.domElement.style.position = "absolute";
|
||||
labelRenderer.domElement.style.top = "0px";
|
||||
document.body.appendChild(labelRenderer.domElement);
|
||||
|
||||
window.addEventListener("resize", onWindowResize);
|
||||
|
||||
let controls = new OrbitControls(camera, labelRenderer.domElement);
|
||||
controls.enablePan = false;
|
||||
controls.minDistance = 10;
|
||||
controls.maxDistance = 14;
|
||||
controls.enableDamping = true;
|
||||
controls.autoRotate = false;
|
||||
|
||||
// <GLOBE>
|
||||
|
||||
let counter = 40000;
|
||||
let rad = 5;
|
||||
let sph = new THREE.Spherical();
|
||||
|
||||
let r = 0;
|
||||
let dlong = Math.PI * (3 - Math.sqrt(5));
|
||||
let dz = 2 / counter;
|
||||
let long = 0;
|
||||
let z = 1 - dz / 2;
|
||||
|
||||
let pts = [];
|
||||
let clr = [];
|
||||
let c = new THREE.Color();
|
||||
let uvs = [];
|
||||
|
||||
for (let i = 0; i < counter; i++) {
|
||||
r = Math.sqrt(1 - z * z);
|
||||
let p = new THREE.Vector3(
|
||||
Math.cos(long) * r,
|
||||
z,
|
||||
-Math.sin(long) * r
|
||||
).multiplyScalar(rad);
|
||||
pts.push(p);
|
||||
z = z - dz;
|
||||
long = long + dlong;
|
||||
|
||||
c.setHSL(0.45, 0.5, Math.random() * 0.25 + 0.25);
|
||||
c.toArray(clr, i * 3);
|
||||
|
||||
sph.setFromVector3(p);
|
||||
uvs.push((sph.theta + Math.PI) / (Math.PI * 2), 1.0 - sph.phi / Math.PI);
|
||||
}
|
||||
|
||||
let g = new THREE.BufferGeometry().setFromPoints(pts);
|
||||
g.setAttribute("color", new THREE.Float32BufferAttribute(clr, 3));
|
||||
g.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));
|
||||
let m = new THREE.PointsMaterial({
|
||||
size: 0.17,
|
||||
vertexColors: false,
|
||||
color: new THREE.Color(0x743c2f),
|
||||
onBeforeCompile: (shader) => {
|
||||
shader.uniforms.globeTexture = {
|
||||
value: new THREE.TextureLoader().load(imgData)
|
||||
const lut = (order) => {
|
||||
const size = 1 << order,
|
||||
area = size * size;
|
||||
const lut = new Float32Array(area);
|
||||
for (let y = 0; y < size; y++)
|
||||
for (let x = 0; x < size; x++)
|
||||
lut[x + y * size] = (bayer(order, x, y) + 0.5) / area;
|
||||
return (x, y) => lut[(x % size) + (y % size) * size];
|
||||
};
|
||||
shader.vertexShader = `
|
||||
uniform sampler2D globeTexture;
|
||||
varying float vVisibility;
|
||||
varying vec3 vNormal;
|
||||
varying vec3 vMvPosition;
|
||||
${shader.vertexShader}
|
||||
`.replace(
|
||||
`gl_PointSize = size;`,
|
||||
`
|
||||
vVisibility = texture(globeTexture, uv).g;
|
||||
gl_PointSize = size * (vVisibility < 0.5 ? 1. : 0.75);
|
||||
vNormal = normalMatrix * normalize(position);
|
||||
vMvPosition = -mvPosition.xyz;
|
||||
gl_PointSize *= 0.4 + (dot(normalize(vMvPosition), vNormal) * 0.6);
|
||||
`
|
||||
);
|
||||
shader.fragmentShader = `
|
||||
varying float vVisibility;
|
||||
varying vec3 vNormal;
|
||||
varying vec3 vMvPosition;
|
||||
${shader.fragmentShader}
|
||||
`.replace(
|
||||
`vec4 diffuseColor = vec4( diffuse, opacity );`,
|
||||
`
|
||||
bool circ = length(gl_PointCoord - 0.5) > 0.5;
|
||||
bool vis = dot(vMvPosition, vNormal) < 0.;
|
||||
if (circ || vis) discard;
|
||||
|
||||
vec3 col = diffuse + (vVisibility > 0.5 ? 0.5 : 0.);
|
||||
// render
|
||||
|
||||
vec4 diffuseColor = vec4( col, opacity );`
|
||||
);
|
||||
const simplex = new SimplexNoise();
|
||||
const bayer4 = lut(4);
|
||||
|
||||
const fbm = (freq, amp, x, y, z) =>
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2) +
|
||||
simplex.noise3D(x * (freq *= 2), y * freq, z * freq) * (amp /= 2);
|
||||
|
||||
const texture = (u, v, w) => (2 * (0.5 + 0.5 * fbm(0.5, 1, u, v, w))) % 1;
|
||||
|
||||
const globe = (x, y, u, v, w) => {
|
||||
const d = u * u + v * v;
|
||||
if (d > 1) return false;
|
||||
|
||||
const f = 1 / ((1 - d ** 0.5) ** 0.5 + 1);
|
||||
const t = texture(1e-1 * w + f * u, f * v, 1e-2 * w);
|
||||
return t > bayer4(x, y);
|
||||
};
|
||||
|
||||
// main
|
||||
|
||||
const main = async () => {
|
||||
const fillerSize = 100;
|
||||
const filler =
|
||||
"\u28ff".repeat(fillerSize) + "\n\u28ff".repeat(fillerSize - 1);
|
||||
|
||||
const root = element("div", { className: "braille" });
|
||||
const hidden = element("div", { className: "hidden", textContent: filler });
|
||||
const visible = element("div", { className: "visible" });
|
||||
|
||||
root.appendChild(hidden);
|
||||
root.appendChild(visible);
|
||||
document.body.appendChild(root);
|
||||
|
||||
for (; ; await frame()) {
|
||||
const hr = hidden.getBoundingClientRect();
|
||||
const fontWidth = hr.width / fillerSize;
|
||||
const fontHeight = hr.height / fillerSize;
|
||||
|
||||
const rr = root.getBoundingClientRect();
|
||||
const ratio = rr.width / rr.height;
|
||||
const width = (rr.width / fontWidth) << 2;
|
||||
const height = (rr.height / fontHeight) << 3;
|
||||
|
||||
const pixels = create(width, height);
|
||||
const time = 1e-3 * Date.now();
|
||||
|
||||
for (let y = 0; y < height; y++) {
|
||||
const v = (2 * y) / height - 1;
|
||||
for (let x = 0; x < width; x++) {
|
||||
const u = ratio * ((2 * x) / width - 1);
|
||||
if (globe(x, y, u, v, time)) set(pixels, x, y);
|
||||
}
|
||||
});
|
||||
let globe = new THREE.Points(g, m);
|
||||
scene.add(globe);
|
||||
// </GLOBE>
|
||||
|
||||
// <LABEL>
|
||||
|
||||
const pinGeometryAtlanta = new THREE.SphereGeometry(0.05, 32, 32);
|
||||
const pinMaterialAtlanta = new THREE.MeshBasicMaterial({ color: 0x31302c });
|
||||
const pinMeshAtlanta = new THREE.Mesh(pinGeometryAtlanta, pinMaterialAtlanta);
|
||||
|
||||
const labelDivAtlanta = document.createElement("div");
|
||||
labelDivAtlanta.className = "label-atl";
|
||||
labelDivAtlanta.textContent = "Atlanta";
|
||||
|
||||
const labelObjectAtlanta = new CSS2DObject(labelDivAtlanta);
|
||||
|
||||
const pinLatitudeAtlanta = 33.7493266;
|
||||
const pinLongitudeAtlanta = -95.39035664;
|
||||
|
||||
const sphericalAtlanta = new THREE.Spherical();
|
||||
sphericalAtlanta.phi = (90 - pinLatitudeAtlanta) * (Math.PI / 180);
|
||||
sphericalAtlanta.theta = (180 - pinLongitudeAtlanta) * (Math.PI / 180);
|
||||
sphericalAtlanta.radius = 5;
|
||||
|
||||
const positionAtlanta = new THREE.Vector3();
|
||||
positionAtlanta.setFromSpherical(sphericalAtlanta);
|
||||
|
||||
pinMeshAtlanta.position.copy(positionAtlanta);
|
||||
labelObjectAtlanta.position.copy(positionAtlanta);
|
||||
|
||||
scene.add(pinMeshAtlanta);
|
||||
scene.add(labelObjectAtlanta);
|
||||
|
||||
// San Jose
|
||||
|
||||
const pinGeometrySanJose = new THREE.SphereGeometry(0.05, 32, 32);
|
||||
const pinMaterialSanJose = new THREE.MeshBasicMaterial({ color: 0x31302c });
|
||||
const pinMeshSanJose = new THREE.Mesh(pinGeometrySanJose, pinMaterialSanJose);
|
||||
|
||||
const labelDivSanJose = document.createElement("div");
|
||||
labelDivSanJose.className = "label-san";
|
||||
labelDivSanJose.textContent = "San Jose";
|
||||
|
||||
const labelObjectSanJose = new CSS2DObject(labelDivSanJose);
|
||||
|
||||
const pinLatitudeSanJose = 38;
|
||||
const pinLongitudeSanJose = -58;
|
||||
|
||||
const sphericalSanJose = new THREE.Spherical();
|
||||
sphericalSanJose.phi = (90 - pinLatitudeSanJose) * (Math.PI / 180);
|
||||
sphericalSanJose.theta = (180 - pinLongitudeSanJose) * (Math.PI / 180);
|
||||
sphericalSanJose.radius = 5;
|
||||
|
||||
const positionSanJose = new THREE.Vector3();
|
||||
positionSanJose.setFromSpherical(sphericalSanJose);
|
||||
|
||||
pinMeshSanJose.position.copy(positionSanJose);
|
||||
labelObjectSanJose.position.copy(positionSanJose);
|
||||
|
||||
scene.add(pinMeshSanJose);
|
||||
scene.add(labelObjectSanJose);
|
||||
|
||||
// Vint Hill
|
||||
|
||||
const pinGeometryVintHill = new THREE.SphereGeometry(0.05, 32, 32);
|
||||
const pinMaterialVintHill = new THREE.MeshBasicMaterial({ color: 0x31302c });
|
||||
const pinMeshVintHill = new THREE.Mesh(
|
||||
pinGeometryVintHill,
|
||||
pinMaterialVintHill
|
||||
);
|
||||
|
||||
const labelDivVintHill = document.createElement("div");
|
||||
labelDivVintHill.className = "label-vint";
|
||||
labelDivVintHill.textContent = "Vint Hill";
|
||||
|
||||
const labelObjectVintHill = new CSS2DObject(labelDivVintHill);
|
||||
|
||||
const pinLatitudeVintHill = 38;
|
||||
const pinLongitudeVintHill = -101;
|
||||
|
||||
const sphericalVintHill = new THREE.Spherical();
|
||||
sphericalVintHill.phi = (90 - pinLatitudeVintHill) * (Math.PI / 180);
|
||||
sphericalVintHill.theta = (180 - pinLongitudeVintHill) * (Math.PI / 180);
|
||||
sphericalVintHill.radius = 5;
|
||||
|
||||
const positionVintHill = new THREE.Vector3();
|
||||
positionVintHill.setFromSpherical(sphericalVintHill);
|
||||
|
||||
pinMeshVintHill.position.copy(positionVintHill);
|
||||
labelObjectVintHill.position.copy(positionVintHill);
|
||||
|
||||
scene.add(pinMeshVintHill);
|
||||
scene.add(labelObjectVintHill);
|
||||
|
||||
// Chicago
|
||||
const pinGeometryChicago = new THREE.SphereGeometry(0.05, 32, 32);
|
||||
const pinMaterialChicago = new THREE.MeshBasicMaterial({ color: 0x31302c });
|
||||
const pinMeshChicago = new THREE.Mesh(pinGeometryChicago, pinMaterialChicago);
|
||||
|
||||
const labelDivChicago = document.createElement("div");
|
||||
labelDivChicago.className = "label-cha";
|
||||
labelDivChicago.textContent = "Chicago";
|
||||
|
||||
const labelObjectChicago = new CSS2DObject(labelDivChicago);
|
||||
|
||||
const pinLatitudeChicago = 42;
|
||||
const pinLongitudeChicago = -92.5;
|
||||
|
||||
const sphericalChicago = new THREE.Spherical();
|
||||
sphericalChicago.phi = (90 - pinLatitudeChicago) * (Math.PI / 180);
|
||||
sphericalChicago.theta = (180 - pinLongitudeChicago) * (Math.PI / 180);
|
||||
sphericalChicago.radius = 5;
|
||||
|
||||
const positionChicago = new THREE.Vector3();
|
||||
positionChicago.setFromSpherical(sphericalChicago);
|
||||
|
||||
pinMeshChicago.position.copy(positionChicago);
|
||||
labelObjectChicago.position.copy(positionChicago);
|
||||
|
||||
scene.add(pinMeshChicago);
|
||||
scene.add(labelObjectChicago);
|
||||
|
||||
// New York
|
||||
const pinGeometryNewYork = new THREE.SphereGeometry(0.05, 32, 32);
|
||||
const pinMaterialNewYork = new THREE.MeshBasicMaterial({ color: 0x31302c });
|
||||
const pinMeshNewYork = new THREE.Mesh(pinGeometryNewYork, pinMaterialNewYork);
|
||||
|
||||
const labelDivNewYork = document.createElement("div");
|
||||
labelDivNewYork.className = "label-york";
|
||||
labelDivNewYork.textContent = "New York";
|
||||
|
||||
const labelObjectNewYork = new CSS2DObject(labelDivNewYork);
|
||||
|
||||
const pinLatitudeNewYork = 40;
|
||||
const pinLongitudeNewYork = -105;
|
||||
|
||||
const sphericalNewYork = new THREE.Spherical();
|
||||
sphericalNewYork.phi = (90 - pinLatitudeNewYork) * (Math.PI / 180);
|
||||
sphericalNewYork.theta = (180 - pinLongitudeNewYork) * (Math.PI / 180);
|
||||
sphericalNewYork.radius = 5;
|
||||
|
||||
const positionNewYork = new THREE.Vector3();
|
||||
positionNewYork.setFromSpherical(sphericalNewYork);
|
||||
|
||||
pinMeshNewYork.position.copy(positionNewYork);
|
||||
labelObjectNewYork.position.copy(positionNewYork);
|
||||
|
||||
scene.add(pinMeshNewYork);
|
||||
scene.add(labelObjectNewYork);
|
||||
|
||||
// ARCS
|
||||
|
||||
function renderArc(startPosition, endPosition) {
|
||||
const curve = new THREE.QuadraticBezierCurve3(
|
||||
startPosition,
|
||||
new THREE.Vector3(
|
||||
(startPosition.x + endPosition.x) / 1.8,
|
||||
(startPosition.y + endPosition.y) / 1.8,
|
||||
(startPosition.z + endPosition.z) / 2
|
||||
),
|
||||
endPosition
|
||||
);
|
||||
|
||||
const points = curve.getPoints(50);
|
||||
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
||||
const material = new THREE.LineBasicMaterial({ color: 0xffffff });
|
||||
|
||||
const arc = new THREE.Line(geometry, material);
|
||||
scene.add(arc);
|
||||
}
|
||||
|
||||
renderArc(positionAtlanta, positionSanJose);
|
||||
renderArc(positionAtlanta, positionNewYork);
|
||||
renderArc(positionAtlanta, positionVintHill);
|
||||
renderArc(positionAtlanta, positionChicago);
|
||||
renderArc(positionSanJose, positionNewYork);
|
||||
renderArc(positionSanJose, positionVintHill);
|
||||
renderArc(positionSanJose, positionChicago);
|
||||
renderArc(positionNewYork, positionVintHill);
|
||||
renderArc(positionNewYork, positionChicago);
|
||||
|
||||
// </LABEL>
|
||||
|
||||
let clock = new THREE.Clock();
|
||||
|
||||
renderer.setAnimationLoop(() => {
|
||||
let t = clock.getElapsedTime();
|
||||
globalUniforms.time.value = t;
|
||||
controls.update();
|
||||
renderer.render(scene, camera);
|
||||
labelRenderer.render(scene, camera);
|
||||
});
|
||||
|
||||
function onWindowResize() {
|
||||
camera.aspect = innerWidth / innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(innerWidth, innerHeight);
|
||||
labelRenderer.setSize(innerWidth, innerHeight);
|
||||
visible.textContent = render(pixels);
|
||||
}
|
||||
};
|
||||
|
||||
main();
|
||||
})();
|
||||
|
|
335
public/style.css
335
public/style.css
|
@ -1,322 +1,49 @@
|
|||
@import url("//cdn.jsdelivr.net/gh/be5invis/Iosevka@ff81c66/fonts.css");
|
||||
|
||||
:root {
|
||||
--size: calc(100vmin / 1.618033988749895);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
}
|
||||
|
||||
.header-container {
|
||||
color: white;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: fixed;
|
||||
top: 1rem;
|
||||
left: 1rem;
|
||||
right: 1rem;
|
||||
color: #fff;
|
||||
z-index: 999;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
backdrop-filter: blur(5px);
|
||||
padding: 1rem;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.header-container h1 {
|
||||
display: inline-block;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header-container nav ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.header-container nav ul li {
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.header-container nav ul li a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font-weight: 800;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-container nav ul li a::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background-color: white;
|
||||
transform: scaleX(0);
|
||||
transform-origin: bottom left;
|
||||
transition: transform 0.3s ease;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.header-container nav ul li a:hover::before {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.card-button {
|
||||
position: fixed;
|
||||
z-index: 99;
|
||||
right: 1.9rem;
|
||||
bottom: 1.9rem;
|
||||
padding: 5px 30px;
|
||||
background-color: #232222;
|
||||
color: #e3e3e3;
|
||||
border-radius: 5px;
|
||||
font-size: 22px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.card-button:hover {
|
||||
animation: wobble 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes wobble {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
15% {
|
||||
transform: translateX(-2px) rotate(-2deg);
|
||||
}
|
||||
30% {
|
||||
transform: translateX(2px) rotate(2deg);
|
||||
}
|
||||
45% {
|
||||
transform: translateX(-1px) rotate(-1deg);
|
||||
}
|
||||
60% {
|
||||
transform: translateX(1px) rotate(1deg);
|
||||
}
|
||||
75% {
|
||||
transform: translateX(-0.5px) rotate(-0.5deg);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.card-out {
|
||||
z-index: 99;
|
||||
position: fixed;
|
||||
right: -520px;
|
||||
bottom: 15px;
|
||||
transition: right 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.card-in {
|
||||
z-index: 99;
|
||||
position: fixed;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
transition: right 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
outline: 0;
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
text-decoration: none;
|
||||
box-sizing: border-box;
|
||||
transition: color 300ms ease-out, background 300ms ease-out,
|
||||
border 300ms ease-out, transform 300ms ease-out, opacity 300ms ease-out;
|
||||
background: #241917;
|
||||
color: #f3bbae;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
options,
|
||||
button {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
font-weight: normal;
|
||||
background: none;
|
||||
color: #b4a477;
|
||||
}
|
||||
|
||||
.card-wrap {
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
max-width: 520px;
|
||||
background-color: #232323;
|
||||
border-radius: 9px;
|
||||
box-shadow: 7px 7px 0 #743c2f;
|
||||
}
|
||||
|
||||
.tabs-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tabs-nav {
|
||||
body,
|
||||
.braille {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: #232222;
|
||||
justify-content: center;
|
||||
flex-flow: row;
|
||||
}
|
||||
|
||||
.tabs-nav > button {
|
||||
flex: 1;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
padding: 0.8em 0;
|
||||
background-color: #232222;
|
||||
font-weight: bold;
|
||||
color: #733c2f;
|
||||
.braille {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
font: 11px/12px "Iosevka Web", monospace;
|
||||
}
|
||||
|
||||
.tabs-nav > button:hover {
|
||||
background-color: #733c2f;
|
||||
color: #232222;
|
||||
.braille > * {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.tabs-nav > button.active {
|
||||
background-color: #733c2f;
|
||||
border-color: #733c2f;
|
||||
color: #232222;
|
||||
.braille .hidden {
|
||||
position: fixed;
|
||||
bottom: 100%;
|
||||
right: 100%;
|
||||
}
|
||||
|
||||
.tabs-info {
|
||||
min-height: 100px;
|
||||
padding-top: 1em;
|
||||
background-color: #232222;
|
||||
font-weight: 700;
|
||||
color: #733c2f;
|
||||
.visible {
|
||||
display: fixed !important;
|
||||
left: 2;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
margin-bottom: 1em;
|
||||
padding: 0 1em;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-qr > img {
|
||||
display: block;
|
||||
border-radius: 10px;
|
||||
background-color: white;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-input {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: stretch;
|
||||
background-color: #232323;
|
||||
padding: 0.75em 1em;
|
||||
box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-input > span {
|
||||
margin-right: 1em;
|
||||
font-weight: bold;
|
||||
color: #733c2f;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-input > input {
|
||||
flex: 1;
|
||||
margin-right: 1em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
color: #733c2f;
|
||||
background-color: #232323;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-input > button {
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
background-color: #232222;
|
||||
color: #733c2f;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-details {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.tabs-info .tabs-info-warn {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.label-york,
|
||||
.label-atl,
|
||||
.label-cha,
|
||||
.label-vint,
|
||||
.label-san {
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.ping1,
|
||||
.ping2,
|
||||
.ping3{position:absolute;z-index:88;left:50%;top:50%;display:block;content:"";-webkit-border-radius:116px;-moz-border-radius:116px;border-radius:116px;border:2px solid #ee4633;
|
||||
transition:all 0.2s ease-in-out;
|
||||
-webkit-transition:all 0.2s ease-in-out;
|
||||
-moz-transition:all 0.2s ease-in-out;
|
||||
-o-transition:all 0.2s ease-in-out;
|
||||
width:0;
|
||||
height:0;
|
||||
margin-left:-2px;
|
||||
margin-top:-2px;}
|
||||
|
||||
.dot:hover .ping1,
|
||||
.dot:hover .ping2,
|
||||
.dot:hover .ping3 {
|
||||
transition:all 0.75s ease-out;
|
||||
-webkit-transition:all 0.75s ease-out;
|
||||
-moz-transition:all 0.75s ease-out;
|
||||
-o-transition:all 0.75s ease-out;
|
||||
}
|
||||
.dot:hover .ping1 { width:116px;height:116px; margin-left:-60px;margin-top:-60px; }
|
||||
.dot:hover .ping2{width:66px;height:66px;margin-left:-35px;margin-top:-35px;
|
||||
-moz-transition-delay:0.2s;
|
||||
-webkit-transition-delay:0.2s;
|
||||
-o-transition-delay:0.2s;
|
||||
transition-delay:0.2s;}
|
||||
.dot:hover .ping3{width:40px;height:40px;margin-left:-22px;margin-top:-22px;
|
||||
-moz-transition-delay:0.5s;
|
||||
-webkit-transition-delay:0.5s;
|
||||
-o-transition-delay:0.5s;
|
||||
transition-delay:0.5s;}
|
||||
|
||||
|
||||
.dot{position:absolute;z-index:99;width:14px;height:14px;background:#ee4633;-webkit-border-radius:12px;-moz-border-radius:12px;border-radius:12px;cursor:pointer;}
|
||||
|
||||
#map{position:relative;margin:5% auto;width:638px;}
|
||||
|
||||
#portland{left:33px;top:50px;}
|
||||
#palo_alto{left:17px;top:181px;}
|
||||
#scottsdale {left:115px;top:246px;}
|
||||
#san_antonio{left:296px;top:311px;}
|
||||
|
|
Loading…
Add table
Reference in a new issue