initial commit

This commit is contained in:
2025-05-29 12:47:28 +02:00
commit a9015c571f
16 changed files with 839 additions and 0 deletions

36
assets/monero.svg Normal file
View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 6000 6000"
height="6000"
width="6000"
xml:space="preserve"
id="svg2"
version="1.1"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
id="clipPath18"
clipPathUnits="userSpaceOnUse"><path
id="path16"
d="M 0,4500 H 4500 V 0 H 0 Z" /></clipPath></defs><g
transform="matrix(1.3333333,0,0,-1.3333333,0,6000)"
id="g10"><g
id="g12"><g
clip-path="url(#clipPath18)"
id="g14"><g
transform="translate(2249.9688,4467.3906)"
id="g20"><path
id="path22"
style="fill:#ff6600;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="m 0,0 c -1224.422,0 -2217.391,-992.906 -2217.391,-2217.359 0,-244.75 39.672,-480.172 112.938,-700.391 h 663.156 v 1865.641 L 0,-2493.438 1441.313,-1052.109 V -2917.75 H 2104.5 c 73.281,220.219 112.953,455.641 112.953,700.391 C 2217.453,-992.906 1224.484,0 0,0" /></g><g
transform="translate(1918.5469,1642.5938)"
id="g24"><path
id="path26"
style="fill:#4c4c4c;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 0,0 -629,629.031 V -544.891 h -240.469 -240.437 -453.438 c 389.25,-638.609 1092.282,-1065.093 1894.735,-1065.093 802.437,0 1505.531,426.484 1894.75,1065.093 h -453.469 -430.063 -50.812 V 629.031 L 662.75,0 331.391,-331.359 0.031,0 Z" /></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

166
assets/script.js Normal file
View File

@@ -0,0 +1,166 @@
// script.js
let currentLanguage = localStorage.getItem("language")
if (!currentLanguage) {
currentLanguage = window.navigator.language.includes("de") ? "de" : "en"
localStorage.setItem("language", currentLanguage)
}
let currentMode = localStorage.getItem("mode")
if (!currentMode) {
currentMode = window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
localStorage.setItem("mode", currentMode)
}
// dark mode toggle
const setInitialMode = () => {
if (currentMode === "dark") {
document.body.classList.remove("light-mode")
document.body.classList.add("dark-mode")
document.querySelector(".mode-switcher").classList.remove("day")
document.querySelector(".mode-switcher .moon").classList.remove("sun")
} else {
document.body.classList.add("light-mode")
document.body.classList.remove("dark-mode")
document.querySelector(".mode-switcher").classList.add("day")
document.querySelector(".mode-switcher .moon").classList.add("sun")
}
}
const toggleMode = () => {
currentMode = currentMode === "light" ? "dark" : "light"
localStorage.setItem("mode", currentMode)
document.body.classList.toggle("light-mode")
document.body.classList.toggle("dark-mode")
document.querySelector(".mode-switcher").classList.toggle("day")
document.querySelector(".mode-switcher .moon").classList.toggle("sun")
}
// loading language files dynamically
loadLanguage = async (lang, save = true) => {
if (save) localStorage.setItem("language", lang)
const response = await fetch(`i18n/${lang}/${lang}.json`)
const translations = await response.json()
document.documentElement.lang = lang
if (translations.website.page_language)
document
.querySelector('meta[name="language"]')
.setAttribute("content", translations.website.page_language)
if (translations.website.page_title)
document.title = translations.website.page_title
if (translations.website.page_description)
document
.querySelector('meta[name="description"]')
.setAttribute("content", translations.website.page_description)
if (translations.website.page_keywords)
document
.querySelector('meta[name="keywords"]')
.setAttribute("content", translations.website.page_keywords)
document.querySelectorAll("[data-i18n]").forEach((el) => {
const key = el.getAttribute("data-i18n")
if (translations.website[key]) {
el.innerHTML = translations.website[key]
}
})
setPreviewImages()
}
// set preview images
const setPreviewImages = () => {
const lang = localStorage.getItem("language") || "en"
const previewLightImage = document.querySelector(".preview-flyer-light img")
const previewDarkImage = document.querySelector(".preview-flyer-dark img")
previewLightImage.src = `./i18n/${lang}/preview-flyer-light.png`
previewDarkImage.src = `./i18n/${lang}/preview-flyer-dark.png`
previewLightImage.alt = `Preview flyer in light mode (${lang})`
previewDarkImage.alt = `Preview flyer in dark mode (${lang})`
const previewLightPdfLinks = document.querySelectorAll(
".preview-flyer-light a"
)
const previewDarkPdfLinks = document.querySelectorAll(".preview-flyer-dark a")
previewLightPdfLinks.forEach((link) => {
link.href = `./i18n/${lang}/flyer-light-${lang}.pdf`
})
previewDarkPdfLinks.forEach((link) => {
link.href = `./i18n/${lang}/flyer-dark-${lang}.pdf`
})
}
// sorting
const categoryOrder = {
comfort: ["cex", "kyc_light", "atomic", "no_kyc", "dex"],
privacy: ["atomic", "dex", "no_kyc", "kyc_light", "cex"],
}
const sortCategories = (mode) => {
const exchanges = document.querySelector("#exchanges")
const blocks = {}
for (const id of Object.values(categoryOrder.comfort)) {
const h2 = document.getElementById(id)
const p = document.getElementById(id + "-desc")
const div = h2.nextElementSibling.nextElementSibling
blocks[id] = [h2, p, div]
}
for (const block of Object.values(blocks).flat()) {
exchanges.removeChild(block)
}
for (const id of categoryOrder[mode]) {
for (const el of blocks[id]) {
exchanges.appendChild(el)
}
}
localStorage.setItem("sortMode", mode)
}
// initial
document.addEventListener("DOMContentLoaded", () => {
// mode
setInitialMode()
// language
const savedLang = localStorage.getItem("language")
const browserLang = navigator.language.slice(0, 2)
const lang = savedLang || browserLang
loadLanguage(lang, true)
// set option with value="lang" as selected
const langSwitcher = document.querySelector(".language-switcher")
langSwitcher.querySelectorAll("option").forEach((option) => {
if (option.value === lang) {
option.selected = true
}
})
// preview images
setPreviewImages()
// sorting
const savedSort = localStorage.getItem("sortMode") || "comfort"
const hasSorting = document.getElementById("sort-mode")
if (hasSorting) {
document.getElementById("sort-mode").value = savedSort
sortCategories(savedSort)
}
})
// current year
document.getElementById("current-year").textContent = new Date().getFullYear()
// micro animation
const elements = document.querySelectorAll(".fade-in")
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("visible")
}
})
})
elements.forEach((el) => observer.observe(el))

251
assets/style.css Normal file
View File

@@ -0,0 +1,251 @@
:root {
--color-monero-orange: #ff6b00;
--color-monero-grey: #4c4c4c;
--background-color: #fffefe;
--text-color: #1d1d1b;
--mode-background-color: #adadad;
--moon-color: #fffefe;
--headline-font: "Raleway", sans-serif;
--text-font: "Poppins", sans-serif;
--font-size-h1: 1.75em;
--font-size-h2: 1.5em;
--font-size-h3: 1.25em;
--font-size-title: 1.2em;
--font-size-text: 1.2em;
--font-size-footer: 1em;
--font-weight-headline: 800;
--font-weight-strong: 500;
--font-weight-text: 200;
--line-height-headline: 1.2;
--line-height-text: 1.6;
--margin-padding-unit: 1em;
--toggle-height: 16em;
--toggle-width: 30em;
--toggle-button-radius: 10em;
--max-width: 640px;
}
:root .dark-mode {
--background-color: #1d1d1b;
--text-color: #fffefe;
--mode-background-color: #4c4c4c;
}
html,
body {
height: 100%;
margin: 0;
}
body {
background-color: var(--background-color);
color: var(--text-color);
font-family: "Poppins", sans-serif;
font-weight: var(--font-weight-text);
font-style: normal;
font-size: var(--font-size-text);
line-height: var(--line-height-text);
padding: 0 1rem;
max-width: 640px;
margin: 0 auto;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--margin-padding-unit) 0;
}
footer {
padding: var(--margin-padding-unit);
text-align: center;
font-size: var(--font-size-footer);
}
select {
background: 0 none;
border: 0 none;
color: var(--text-color);
font-size: var(--font-size-text);
font-family: "Poppins", sans-serif;
font-weight: 100;
font-style: normal;
}
option {
font-size: 2rem;
font-family: "Poppins", sans-serif;
font-weight: 100;
font-style: normal;
}
/* mode switcher */
.mode-switcher {
cursor: pointer;
margin: 0 auto;
/*change size of toggle with font-size*/
font-size: 10%;
position: relative;
height: var(--toggle-height);
width: var(--toggle-width);
border-radius: var(--toggle-height);
transition: all 0.5s ease-in-out;
background: var(--mode-background-color);
}
.moon {
position: absolute;
display: block;
border-radius: 50%;
transition: all 0.4s ease-in-out;
top: 3em;
left: 3em;
transform: rotate(-75deg);
width: var(--toggle-button-radius);
height: var(--toggle-button-radius);
background: var(--theme-color-dark);
box-shadow: 3em 2.5em 0 0em var(--moon-color) inset,
rgba(255, 255, 255, 0.1) 0em -7em 0 -4.5em,
rgba(255, 255, 255, 0.1) 3em 7em 0 -4.5em,
rgba(255, 255, 255, 0.1) 2em 13em 0 -4em,
rgba(255, 255, 255, 0.1) 6em 2em 0 -4.1em,
rgba(255, 255, 255, 0.1) 8em 8em 0 -4.5em,
rgba(255, 255, 255, 0.1) 6em 13em 0 -4.5em,
rgba(255, 255, 255, 0.1) -4em 7em 0 -4.5em,
rgba(255, 255, 255, 0.1) -1em 10em 0 -4.5em;
}
.sun {
top: 4.5em;
left: 18em;
transform: rotate(0deg);
width: 7em;
height: 7em;
background: #fff;
box-shadow: 3em 3em 0 5em #fff inset, 0 -5em 0 -2.7em #fff,
3.5em -3.5em 0 -3em #fff, 5em 0 0 -2.7em #fff, 3.5em 3.5em 0 -3em #fff,
0 5em 0 -2.7em #fff, -3.5em 3.5em 0 -3em #fff, -5em 0 0 -2.7em #fff,
-3.5em -3.5em 0 -3em #fff;
}
.day {
background: var(--mode-background-color);
}
h1,
h2,
h3 {
font-family: var(--headline-font);
font-size: var(--font-size-h1);
font-weight: var(--font-weight-headline);
line-height: var(--line-height-headline);
margin: var(--margin-padding-unit) 0;
text-transform: uppercase;
}
h2 {
font-size: var(--font-size-h2);
}
h3 {
font-size: var(--font-size-h3);
}
strong {
font-weight: var(--font-weight-strong);
}
a {
border: 0 none;
border-bottom: 1px solid var(--color-monero-orange);
color: var(--color-monero-orange);
text-decoration: none;
}
a:hover {
border-color: var(--text-color) !important;
border-style: dashed;
color: var(--text-color) !important;
}
a:hover strong {
color: var(--text-color) !important;
}
.monero-orange {
color: var(--color-monero-orange);
}
.monero-grey {
color: var(--color-monero-grey);
}
ul {
padding-left: 20px;
}
.logo {
display: block;
width: 100px;
height: auto;
transition: transform 0.3s ease-in-out;
}
.logo:hover {
transform: scale(1.05);
transition: transform 0.3s ease-in-out;
}
.fade-in {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.fade-in.visible {
opacity: 1;
transform: translateY(0);
}
.preview-images {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.preview-images > div {
width: 100%;
height: auto;
}
.preview-images > div:first-child {
margin-bottom: 1rem;
}
.preview-images img {
display: block;
width: 100%;
height: auto;
border-radius: 8px;
transition: transform 0.3s ease-in-out;
}
.preview-images img:hover {
transform: scale(1.05);
}
@media screen and (min-width: 768px) {
.preview-images div {
width: calc(50% - 0.5rem);
}
.preview-images > div:first-child {
margin-bottom: 0;
}
}