diff options
Diffstat (limited to 'assets')
51 files changed, 2658 insertions, 0 deletions
diff --git a/assets/css/inline-attrs.css b/assets/css/inline-attrs.css new file mode 100644 index 0000000..2dce580 --- /dev/null +++ b/assets/css/inline-attrs.css @@ -0,0 +1,31 @@ +.s1da9facb4d{margin:0;} +.s6e250fe32e{border:none;border-top:1px solid #caa;margin:1rem 0;} +.s2a2536eebb{margin: 15px 0;} +.sd078564312{border:1px solid #ffd; display:block; margin-bottom:6px;} +.sd82634530e{background: transparent; + border:1px solid transparent; + color:#3a2a00; + padding:10px; + width:100%; + border-radius:4px;} +.sefd85b92cb{display: flex; flex-direction: column; gap: 20px;} +.s0b3fba4969{border: 1px solid var(--border); border-radius: var(--r);} +.see3e7269f8{height:700px; border: 1px solid var(--border); border-radius: var(--r);} +.s9572e08b37{width:150px;opacity:0.7;} +.se7f7a3d62d{border:1px solid var(--border);border-radius:var(--r);padding:var(--space-md);background:var(--bg);overflow:auto;} +.s06eeebc88f{max-width: 100%; height: auto;} +.s386d82bd1c{height:1100px;} +.s7e8ca45906{font-size: 50px;} +.s0667eb5585{max-width:160px;border:1px solid var(--border);border-radius:var(--r);background:var(--bg);} +.sed328f664c{min-height:360px;} +.s63501a3337{border:1px solid var(--border);border-radius:var(--r);background:var(--bg);} +.saf481e1471{width:100%;max-width:560px;height:315px;border:1px solid var(--border);border-radius:var(--r);} +.sb83d4c5326{max-width:720px;margin:0 auto;border:1px solid var(--border);border-radius:var(--r);background:var(--bg);} +.sd1a2ffa0b4{text-align:center;margin-top:var(--space-md);} +.sdac4fe6c9b{text-align:center;} +.sfed215d685{max-width:420px;margin:0 auto;border:1px solid var(--border);border-radius:var(--r);background:var(--bg);} +.s16a8a8b00c{overflow:auto;} +.s473e6bbfeb{width:100%;border-collapse:collapse;} +.sf2e940dbbf{text-align:left;border-bottom:1px solid var(--border);padding:8px;} +.s6f279abaab{padding:8px;border-bottom:1px dotted var(--border);} +.s44cd1236df{padding:8px;} diff --git a/assets/css/pages/404.css b/assets/css/pages/404.css new file mode 100644 index 0000000..7939cc1 --- /dev/null +++ b/assets/css/pages/404.css @@ -0,0 +1,12 @@ +/* Minimal fallback if CSS fails to load */ + body{margin:0;background:#ffd;color:#000;font-family:system-ui,Segoe UI,Arial,sans-serif;line-height:1.6;} + .wrap{max-width:960px;margin:0 auto;padding:1.35rem 1rem 2.5rem;} + .card{border:1px solid #caa;border-radius:6px;padding:1rem;background:#ffd;} + .top{display:flex;gap:12px;align-items:center;margin-bottom:1rem;} + .top img{width:48px;height:48px;border:2px solid #000;border-radius:6px;} + .top a:hover img{border-color:#d22;} + a{color:#d22;text-decoration:none;transition:0.1s;} + a:hover{background:#d22;color:#000 !important;} + .muted{color:#333;font-size:.9rem;} + .links{margin:1rem 0 0 0;} + .links a{display:inline-block;margin:0 .25rem .5rem 0;padding:2px 4px;border-radius:4px;} diff --git a/assets/css/pages/50x.css b/assets/css/pages/50x.css new file mode 100644 index 0000000..cc573de --- /dev/null +++ b/assets/css/pages/50x.css @@ -0,0 +1,9 @@ +body{margin:0;background:#ffd;color:#000;font-family:system-ui,Segoe UI,Arial,sans-serif;line-height:1.6;} + .wrap{max-width:960px;margin:0 auto;padding:1.35rem 1rem 2.5rem;} + .card{border:1px solid #caa;border-radius:6px;padding:1rem;background:#ffd;} + .top{display:flex;gap:12px;align-items:center;margin-bottom:1rem;} + .top img{width:48px;height:48px;border:2px solid #000;border-radius:6px;} + .top a:hover img{border-color:#d22;} + a{color:#d22;text-decoration:none;transition:0.1s;} + a:hover{background:#d22;color:#000 !important;} + .muted{color:#333;font-size:.9rem;} diff --git a/assets/css/pages/articles-2023-04-10.css b/assets/css/pages/articles-2023-04-10.css new file mode 100644 index 0000000..1818de4 --- /dev/null +++ b/assets/css/pages/articles-2023-04-10.css @@ -0,0 +1 @@ +kbd{ border:1px solid var(--border); border-radius:4px; padding:0 6px; background: #fff; } diff --git a/assets/css/pages/articles-2023-04-10_jp.css b/assets/css/pages/articles-2023-04-10_jp.css new file mode 100644 index 0000000..1818de4 --- /dev/null +++ b/assets/css/pages/articles-2023-04-10_jp.css @@ -0,0 +1 @@ +kbd{ border:1px solid var(--border); border-radius:4px; padding:0 6px; background: #fff; } diff --git a/assets/css/pages/articles-2023-04-10_zh.css b/assets/css/pages/articles-2023-04-10_zh.css new file mode 100644 index 0000000..1818de4 --- /dev/null +++ b/assets/css/pages/articles-2023-04-10_zh.css @@ -0,0 +1 @@ +kbd{ border:1px solid var(--border); border-radius:4px; padding:0 6px; background: #fff; } diff --git a/assets/css/pages/articles-runescape.css b/assets/css/pages/articles-runescape.css new file mode 100644 index 0000000..1818de4 --- /dev/null +++ b/assets/css/pages/articles-runescape.css @@ -0,0 +1 @@ +kbd{ border:1px solid var(--border); border-radius:4px; padding:0 6px; background: #fff; } diff --git a/assets/css/pages/articles-runescape_jp.css b/assets/css/pages/articles-runescape_jp.css new file mode 100644 index 0000000..1818de4 --- /dev/null +++ b/assets/css/pages/articles-runescape_jp.css @@ -0,0 +1 @@ +kbd{ border:1px solid var(--border); border-radius:4px; padding:0 6px; background: #fff; } diff --git a/assets/css/pages/articles-runescape_zh.css b/assets/css/pages/articles-runescape_zh.css new file mode 100644 index 0000000..1818de4 --- /dev/null +++ b/assets/css/pages/articles-runescape_zh.css @@ -0,0 +1 @@ +kbd{ border:1px solid var(--border); border-radius:4px; padding:0 6px; background: #fff; } diff --git a/assets/css/pages/bookmarks.css b/assets/css/pages/bookmarks.css new file mode 100644 index 0000000..945b771 --- /dev/null +++ b/assets/css/pages/bookmarks.css @@ -0,0 +1,61 @@ +.bookmarks-title{ + margin-bottom: var(--space-md); +} + +.tree{ list-style-type: none; padding-left: 0; margin: 0; } + +.tree ul{ list-style-type: none; padding-left: 28px; margin: 5px 0; } + +.tree li{ margin: 4px 0; position: relative; } + +.tree summary{ + display: flex; + align-items: center; + cursor: pointer; + padding: 8px 12px; + transition: background-color 0.2s ease; + font-weight: 600; + outline: none; + user-select: none; + background: var(--bg); + border: 1px solid var(--border); + border-radius: var(--r); +} + +.tree summary:hover{ background-color: #fdd; border-color: var(--accent); } + +.tree summary::-webkit-details-marker{ display: none; } + +.tree summary::before{ + content: ">"; + color: var(--ink); + margin-right: 10px; + font-size: 1rem; + transition: all 0.2s ease; + width: 20px; + text-align: left; + font-weight: 700; +} + +.tree details[open] > summary::before{ content: ">"; transform: rotate(90deg); } + +.tree a{ + color: var(--ink); + text-decoration: none; + display: inline-flex; + align-items: center; + padding: 6px 6px; + border-radius: 4px; +} + +.tree a:hover{ background: var(--accent); color: #000 !important; } + + +.tree .navbar-file a{ color: var(--muted); } + +.tree .navbar-file a::before{ + content: "->"; + color: var(--muted); + margin-right: 10px; + font-size: 0.9rem; +} diff --git a/assets/css/pages/changelog.css b/assets/css/pages/changelog.css new file mode 100644 index 0000000..78b2ff4 --- /dev/null +++ b/assets/css/pages/changelog.css @@ -0,0 +1,19 @@ +.changelog-list{ list-style: none; padding: 0; margin: 0; } + +.changelog-entry{ + display: grid; + grid-template-columns: 12ch 1fr; + gap: var(--space-lg); + padding: var(--space-md) 0; + border-bottom: 1px dotted rgba(0,0,0,.25); +} + +.changelog-entry:last-child{ border-bottom: none; } + +.changelog-entry time{ font-weight: 700; color: var(--ink); white-space: nowrap; } + +.changelog-entry .text{ color: var(--muted); } + +@media (max-width: 560px){ + .changelog-entry{ grid-template-columns: 1fr; } +} diff --git a/assets/css/pages/computers.css b/assets/css/pages/computers.css new file mode 100644 index 0000000..ec7d01f --- /dev/null +++ b/assets/css/pages/computers.css @@ -0,0 +1,29 @@ +.machine{ + border: 1px solid var(--ink); + padding: var(--space-md); + margin-top: var(--space-md); + background: var(--bg); + display: grid; + grid-template-columns: 150px auto 150px; + gap: var(--space-md); + align-items: start; +} + +.machine img{ + width: 100%; + height: auto; + border: 1px solid var(--ink); +} + +.machine-info{ font-size: var(--fs-base); } + +.machine-title{ + color: var(--gold); + font-weight: 700; + font-size: var(--fs-lg); + margin-bottom: var(--space-xs); +} + +@media (max-width: 720px){ + .machine{ grid-template-columns: 1fr; } +} diff --git a/assets/css/pages/guestbook-form.css b/assets/css/pages/guestbook-form.css new file mode 100644 index 0000000..b45feaa --- /dev/null +++ b/assets/css/pages/guestbook-form.css @@ -0,0 +1,51 @@ +/* Pure light theme — NO container, NO black */ +body { + background: transparent; + margin: 0; + padding: 10px; + font-family: "Source Code Pro", monospace; + color: #3a2a00; + overflow-y: auto; + overflow-x: hidden; + /* Hide scrollbar for Chrome, Safari and Opera */ + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} +body::-webkit-scrollbar { + width: 0; + height: 0; +} + +/* Remove all container styling */ +form { + max-width: 900px; + margin: 0 auto; +} + +/* Slight spacing between form and messages */ +form { + margin-bottom: 20px; +} + +input[type="text"], textarea { + border: 1px solid transparent; + background: transparent; + color: #3a2a00; + font: inherit; + box-sizing: border-box; /* Include padding in width */ + margin-bottom: 10px; +} + +textarea { + resize: vertical; +} + +button { + background: transparent; + border: 1px solid transparent; + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font: inherit; + color: #3a2a00; +} diff --git a/assets/css/pages/guestbook_jp.css b/assets/css/pages/guestbook_jp.css new file mode 100644 index 0000000..bd71cb5 --- /dev/null +++ b/assets/css/pages/guestbook_jp.css @@ -0,0 +1,29 @@ +.anonymous { color: #0a0; } + .error { color: var(--accent); } + .captcha { font-weight: 700; font-size: 20px; } + form { display: grid; gap: var(--space-sm); max-width: 640px; } + label { font-weight: 600; } + input[type="text"], textarea { + width: 100%; + padding: 10px; + border: 1px solid var(--border); + border-radius: var(--r); + background: var(--bg); + color: var(--ink); + font: inherit; + } + textarea { min-height: 120px; resize: vertical; } + .btn-row { display: flex; gap: var(--space-sm); flex-wrap: wrap; } + button { + border: 1px solid var(--border); + border-radius: var(--r); + background: var(--bg); + padding: 8px 12px; + cursor: pointer; + font: inherit; + } + button:hover { background: #fdd; border-color: var(--accent); } + .entry { border-top: 1px dotted rgba(0,0,0,.25); padding-top: var(--space-md); margin-top: var(--space-md); } + .entry h4 { margin: 0 0 var(--space-xs) 0; } + .entry p { margin: 0; color: var(--muted); } + #captcha-canvas { border: 1px solid var(--border); border-radius: var(--r); background: #fff; } diff --git a/assets/css/pages/guestbook_zh.css b/assets/css/pages/guestbook_zh.css new file mode 100644 index 0000000..bd71cb5 --- /dev/null +++ b/assets/css/pages/guestbook_zh.css @@ -0,0 +1,29 @@ +.anonymous { color: #0a0; } + .error { color: var(--accent); } + .captcha { font-weight: 700; font-size: 20px; } + form { display: grid; gap: var(--space-sm); max-width: 640px; } + label { font-weight: 600; } + input[type="text"], textarea { + width: 100%; + padding: 10px; + border: 1px solid var(--border); + border-radius: var(--r); + background: var(--bg); + color: var(--ink); + font: inherit; + } + textarea { min-height: 120px; resize: vertical; } + .btn-row { display: flex; gap: var(--space-sm); flex-wrap: wrap; } + button { + border: 1px solid var(--border); + border-radius: var(--r); + background: var(--bg); + padding: 8px 12px; + cursor: pointer; + font: inherit; + } + button:hover { background: #fdd; border-color: var(--accent); } + .entry { border-top: 1px dotted rgba(0,0,0,.25); padding-top: var(--space-md); margin-top: var(--space-md); } + .entry h4 { margin: 0 0 var(--space-xs) 0; } + .entry p { margin: 0; color: var(--muted); } + #captcha-canvas { border: 1px solid var(--border); border-radius: var(--r); background: #fff; } diff --git a/assets/css/pages/hitcounter.css b/assets/css/pages/hitcounter.css new file mode 100644 index 0000000..1c52da1 --- /dev/null +++ b/assets/css/pages/hitcounter.css @@ -0,0 +1,7 @@ +.counter { + display: grid; + gap: var(--space-sm); + justify-items: center; + text-align: center; + } + .big { font-size: 3rem; font-weight: 800; color: var(--gold); } diff --git a/assets/css/pages/hitcounter_jp.css b/assets/css/pages/hitcounter_jp.css new file mode 100644 index 0000000..1c52da1 --- /dev/null +++ b/assets/css/pages/hitcounter_jp.css @@ -0,0 +1,7 @@ +.counter { + display: grid; + gap: var(--space-sm); + justify-items: center; + text-align: center; + } + .big { font-size: 3rem; font-weight: 800; color: var(--gold); } diff --git a/assets/css/pages/hitcounter_zh.css b/assets/css/pages/hitcounter_zh.css new file mode 100644 index 0000000..1c52da1 --- /dev/null +++ b/assets/css/pages/hitcounter_zh.css @@ -0,0 +1,7 @@ +.counter { + display: grid; + gap: var(--space-sm); + justify-items: center; + text-align: center; + } + .big { font-size: 3rem; font-weight: 800; color: var(--gold); } diff --git a/assets/css/pages/journal-index.css b/assets/css/pages/journal-index.css new file mode 100644 index 0000000..02e8c42 --- /dev/null +++ b/assets/css/pages/journal-index.css @@ -0,0 +1,3 @@ +.entry { margin: var(--space-md) 0; } + .entry time { font-weight: 700; color: var(--ink); } + .entry p { margin: var(--space-xs) 0 0 0; color: var(--muted); } diff --git a/assets/css/pages/journal-index_jp.css b/assets/css/pages/journal-index_jp.css new file mode 100644 index 0000000..02e8c42 --- /dev/null +++ b/assets/css/pages/journal-index_jp.css @@ -0,0 +1,3 @@ +.entry { margin: var(--space-md) 0; } + .entry time { font-weight: 700; color: var(--ink); } + .entry p { margin: var(--space-xs) 0 0 0; color: var(--muted); } diff --git a/assets/css/pages/journal-index_zh.css b/assets/css/pages/journal-index_zh.css new file mode 100644 index 0000000..02e8c42 --- /dev/null +++ b/assets/css/pages/journal-index_zh.css @@ -0,0 +1,3 @@ +.entry { margin: var(--space-md) 0; } + .entry time { font-weight: 700; color: var(--ink); } + .entry p { margin: var(--space-xs) 0 0 0; color: var(--muted); } diff --git a/assets/css/pages/links.css b/assets/css/pages/links.css new file mode 100644 index 0000000..fbb3700 --- /dev/null +++ b/assets/css/pages/links.css @@ -0,0 +1,3 @@ +.buttons img { image-rendering: auto; } + .buttons a { padding: 0; background: transparent; } + .buttons a:hover { background: transparent; } diff --git a/assets/css/pages/links_jp.css b/assets/css/pages/links_jp.css new file mode 100644 index 0000000..fbb3700 --- /dev/null +++ b/assets/css/pages/links_jp.css @@ -0,0 +1,3 @@ +.buttons img { image-rendering: auto; } + .buttons a { padding: 0; background: transparent; } + .buttons a:hover { background: transparent; } diff --git a/assets/css/pages/links_zh.css b/assets/css/pages/links_zh.css new file mode 100644 index 0000000..fbb3700 --- /dev/null +++ b/assets/css/pages/links_zh.css @@ -0,0 +1,3 @@ +.buttons img { image-rendering: auto; } + .buttons a { padding: 0; background: transparent; } + .buttons a:hover { background: transparent; } diff --git a/assets/css/pages/mstartpage-index.css b/assets/css/pages/mstartpage-index.css new file mode 100644 index 0000000..67eac23 --- /dev/null +++ b/assets/css/pages/mstartpage-index.css @@ -0,0 +1,361 @@ +:root { + --main-text-color: #ddd; + --border-color: #C8A977; + --search-input-color: black; + --link-color: #FF0000; + --background-color: #111; + --menu-background: #222; + } + + * { + box-sizing: border-box; + } + + html, body { + margin: 0; + padding: 0; + height: 100%; + background-color: var(--background-color); + font-family: 'Source Code Pro', "MS Gothic", IPAMonaGothic, IPAGothic, "BIZ UDGothic", HGGothicM, "Noto Sans Mono CJK JP", "Noto Sans Mono", monospace; + font-size: 14px; + color: var(--main-text-color); + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7); + overflow-x: hidden; + } + + a { + color: var(--link-color); + background-color: transparent; + text-decoration: none; + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8); + } + + a:hover { + text-decoration: underline; + } + + /* Header and menu */ + .header { + position: sticky; + top: 0; + z-index: 100; + background-color: var(--background-color); + padding: 10px; + border-bottom: 1px solid var(--border-color); + } + + .menu-toggle { + display: block; + width: 100%; + padding: 12px; + background-color: black; + color: var(--link-color); + border: 1px solid var(--link-color); + border-radius: 4px; + text-align: center; + font-weight: bold; + margin-bottom: 10px; + cursor: pointer; + } + + .main-menu { + display: none; + flex-direction: column; + background-color: var(--menu-background); + border: 1px solid var(--link-color); + border-radius: 4px; + padding: 10px; + margin-bottom: 15px; + } + + .main-menu.show { + display: flex; + } + + .main-menu a { + padding: 10px; + border-bottom: 1px solid #333; + } + + .main-menu a:last-child { + border-bottom: none; + } + + /* Search box */ + .search-container { + width: 100%; + padding: 10px; + background-color: var(--background-color); + margin-bottom: 15px; + } + + .search-form { + display: flex; + flex-direction: column; + } + + .search-input { + color: var(--link-color); + background-color: #3A3A3A; + border: 1px solid var(--link-color); + padding: 12px; + margin-bottom: 10px; + text-align: center; + border-radius: 4px; + font-size: 16px; /* Larger for touch */ + } + + input[type="submit"] { + color: var(--link-color); + background-color: black; + padding: 12px; + border: 1px solid var(--link-color); + cursor: pointer; + border-radius: 4px; + font-weight: bold; + font-size: 16px; + } + + /* Content sections */ + .content-section { + margin-bottom: 20px; + padding: 0 10px; + } + + .section-title { + color: var(--link-color); + font-size: 1.2em; + border-bottom: 1px solid var(--border-color); + padding-bottom: 5px; + margin-bottom: 10px; + } + + .link-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + gap: 10px; + } + + .link-item { + padding: 10px; + background-color: #1a1a1a; + border: 1px solid #333; + border-radius: 4px; + text-align: center; + } + + /* Gallery items for mobile */ + .gallery-container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 15px; + padding: 10px; + } + + .gallery-item { + border: 2px ridge var(--border-color); + border-radius: 4px; + overflow: hidden; + } + + .gallery-item:hover { + border: 2px ridge var(--link-color); + } + + .gallery-item img { + width: 100%; + height: auto; + display: block; + } + + .gallery-desc { + padding: 8px; + text-align: center; + font-size: 0.9em; + color: var(--link-color); + background-color: #1a1a1a; + } + + /* Date and time */ + .datetime { + padding: 10px; + text-align: center; + margin: 15px 0; + } + + #realtime-date, #realtime-clock { + color: var(--link-color); + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8); + margin: 5px 0; + } + + /* Footer */ + .footer { + padding: 15px; + text-align: center; + border-top: 1px solid #333; + margin-top: 20px; + } + + .footer-links { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 10px; + } + + .footer-links a { + padding: 5px; + } + + /* Collapsible sections */ + .collapsible { + background-color: #1a1a1a; + color: var(--link-color); + cursor: pointer; + padding: 12px; + width: 100%; + border: 1px solid var(--border-color); + text-align: left; + outline: none; + font-size: 1em; + font-weight: bold; + margin-bottom: 5px; + border-radius: 4px; + } + + .active, .collapsible:hover { + background-color: #222; + } + + .collapsible-content { + padding: 0 10px; + display: none; + overflow: hidden; + background-color: #1a1a1a; + margin-bottom: 10px; + border-radius: 0 0 4px 4px; + } + + /* XXX Verification Modal */ + .xxx-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.9); + z-index: 1000; + justify-content: center; + align-items: center; + } + + .xxx-modal-content { + background-color: var(--menu-background); + padding: 20px; + border-radius: 8px; + border: 2px solid var(--link-color); + text-align: center; + max-width: 90%; + width: 350px; + } + + .xxx-logo { + width: 80px; + height: 80px; + margin: 0 auto 15px; + background-color: #333; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + font-size: 24px; + color: var(--link-color); + border: 2px solid var(--link-color); + } + + .xxx-buttons { + display: flex; + justify-content: space-between; + margin-top: 20px; + } + + .xxx-button { + padding: 10px 20px; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: bold; + } + + .xxx-confirm { + background-color: #4CAF50; + color: white; + } + + .xxx-deny { + background-color: #f44336; + color: white; + } + + /* XXX Section */ + .xxx-section { + margin: 20px 0; + text-align: center; + } + + .xxx-toggle { + padding: 12px 20px; + background-color: #333; + color: var(--link-color); + border: 1px solid var(--link-color); + border-radius: 4px; + cursor: pointer; + font-weight: bold; + margin-bottom: 15px; + } + + .xxx-list { + position: fixed; + bottom: 20px; + right: 20px; + background-color: var(--menu-background); + border: 1px solid var(--link-color); + border-radius: 8px; + padding: 10px; + max-width: 200px; + display: none; + z-index: 999; + } + + .xxx-list-title { + color: var(--link-color); + font-weight: bold; + margin-bottom: 8px; + text-align: center; + border-bottom: 1px solid #444; + padding-bottom: 5px; + } + + .xxx-list-item { + margin: 5px 0; + text-align: center; + } + + /* Responsive adjustments */ + @media (min-width: 768px) { + body { + font-size: 16px; + max-width: 800px; + margin: 0 auto; + } + + .link-grid { + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + } + + .gallery-container { + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + } + } diff --git a/assets/css/pages/startpage-test.css b/assets/css/pages/startpage-test.css new file mode 100644 index 0000000..14996cb --- /dev/null +++ b/assets/css/pages/startpage-test.css @@ -0,0 +1,86 @@ +body { + font-family: 'Inter', sans-serif; /* Using Inter font */ + margin: 0; /* Remove default body margin */ + padding: 20px; + background-color: #f0f0f0; + display: flex; + flex-direction: column; /* Arrange content vertically */ + justify-content: center; + align-items: center; + min-height: 100vh; + } + + h1 { + text-align: center; + color: #333; + margin-bottom: 20px; + font-size: 2em; /* Larger heading */ + } + + .responsive-container { + width: 95%; /* Make it wider to accommodate the full page embed */ + max-width: 1200px; /* Max width for larger screens to prevent it from getting too wide */ + padding: 10px; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 12px; /* Slightly larger rounded corners */ + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15); /* More prominent shadow */ + background-color: white; + margin-bottom: 20px; + overflow: hidden; /* Ensure content stays within rounded corners */ + } + + .iframe-wrapper { + position: relative; + /* Maintain an aspect ratio that suits a full webpage, e.g., 16:9 or taller */ + /* A good starting point for a full webpage, adjust as needed for optimal viewing */ + padding-bottom: 120%; /* Height will be 120% of the width, making it taller */ + height: 0; + overflow: hidden; + border-radius: 8px; /* Slightly smaller rounded corners for inner frame */ + } + + .iframe-wrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: none; + border-radius: 8px; + } + + .desc { + padding: 15px; + text-align: center; + font-size: 1.1em; + color: #555; + line-height: 1.6; + } + + .desc a { + color: #007bff; + text-decoration: none; + font-weight: bold; + transition: color 0.3s ease; /* Smooth transition for hover effect */ + } + + .desc a:hover { + text-decoration: underline; + color: #0056b3; /* Darker blue on hover */ + } + + /* Responsive adjustments for the container */ + @media only screen and (max-width: 768px) { + .responsive-container { + width: 100%; /* Full width on smaller screens */ + padding: 5px; + border-radius: 0; /* No rounded corners on very small screens for edge-to-edge */ + } + .iframe-wrapper { + padding-bottom: 150%; /* Make it even taller on mobile if needed */ + } + body { + padding: 10px; + } + } diff --git a/assets/css/pages/test.css b/assets/css/pages/test.css new file mode 100644 index 0000000..4eacfa4 --- /dev/null +++ b/assets/css/pages/test.css @@ -0,0 +1,52 @@ +html, body { margin: 0; padding: 0; } + table.layout { border-collapse: collapse; width: 100%; } + td.content { padding: 0; } + .logo { float: left; margin-right: 1rem; } + + a { + text-decoration: none; + background-color: transparent; + transition: background-color 0.2s, color 0.2s; + padding: 4px; + border-radius: 4px; + } + a:hover { background-color: red; color: white; } + a.no-hover-box:hover { background-color: transparent; color: red; } + + .sidebar { + position: fixed; + top: 0; + right: 0; + width: 250px; + max-height: 100vh; + overflow-y: auto; + background-color: #ffd; + transform: translateX(100%); + transition: transform 0.3s ease-in-out; + } + .sidebar.visible { transform: translateX(0); } + + .links-container { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + margin-bottom: 1rem; + } + .links-container ul { + flex: 1 1 200px; + list-style: none; + margin: 0; padding: 0; + } + .links-container ul li { margin-bottom: 0.75rem; word-wrap: break-word; } + .links-container ul li a { + display: inline-block; + max-width: 100%; + word-wrap: break-word; + color: #0366d6; + transition: color 0.3s ease; + } + .links-container ul li a:hover { color: #023e8a; text-decoration: underline; } + + @media (max-width: 600px) { + .links-container { flex-direction: column; } + } diff --git a/assets/css/pages/test_jp.css b/assets/css/pages/test_jp.css new file mode 100644 index 0000000..4eacfa4 --- /dev/null +++ b/assets/css/pages/test_jp.css @@ -0,0 +1,52 @@ +html, body { margin: 0; padding: 0; } + table.layout { border-collapse: collapse; width: 100%; } + td.content { padding: 0; } + .logo { float: left; margin-right: 1rem; } + + a { + text-decoration: none; + background-color: transparent; + transition: background-color 0.2s, color 0.2s; + padding: 4px; + border-radius: 4px; + } + a:hover { background-color: red; color: white; } + a.no-hover-box:hover { background-color: transparent; color: red; } + + .sidebar { + position: fixed; + top: 0; + right: 0; + width: 250px; + max-height: 100vh; + overflow-y: auto; + background-color: #ffd; + transform: translateX(100%); + transition: transform 0.3s ease-in-out; + } + .sidebar.visible { transform: translateX(0); } + + .links-container { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + margin-bottom: 1rem; + } + .links-container ul { + flex: 1 1 200px; + list-style: none; + margin: 0; padding: 0; + } + .links-container ul li { margin-bottom: 0.75rem; word-wrap: break-word; } + .links-container ul li a { + display: inline-block; + max-width: 100%; + word-wrap: break-word; + color: #0366d6; + transition: color 0.3s ease; + } + .links-container ul li a:hover { color: #023e8a; text-decoration: underline; } + + @media (max-width: 600px) { + .links-container { flex-direction: column; } + } diff --git a/assets/css/pages/test_zh.css b/assets/css/pages/test_zh.css new file mode 100644 index 0000000..4eacfa4 --- /dev/null +++ b/assets/css/pages/test_zh.css @@ -0,0 +1,52 @@ +html, body { margin: 0; padding: 0; } + table.layout { border-collapse: collapse; width: 100%; } + td.content { padding: 0; } + .logo { float: left; margin-right: 1rem; } + + a { + text-decoration: none; + background-color: transparent; + transition: background-color 0.2s, color 0.2s; + padding: 4px; + border-radius: 4px; + } + a:hover { background-color: red; color: white; } + a.no-hover-box:hover { background-color: transparent; color: red; } + + .sidebar { + position: fixed; + top: 0; + right: 0; + width: 250px; + max-height: 100vh; + overflow-y: auto; + background-color: #ffd; + transform: translateX(100%); + transition: transform 0.3s ease-in-out; + } + .sidebar.visible { transform: translateX(0); } + + .links-container { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + margin-bottom: 1rem; + } + .links-container ul { + flex: 1 1 200px; + list-style: none; + margin: 0; padding: 0; + } + .links-container ul li { margin-bottom: 0.75rem; word-wrap: break-word; } + .links-container ul li a { + display: inline-block; + max-width: 100%; + word-wrap: break-word; + color: #0366d6; + transition: color 0.3s ease; + } + .links-container ul li a:hover { color: #023e8a; text-decoration: underline; } + + @media (max-width: 600px) { + .links-container { flex-direction: column; } + } diff --git a/assets/css/pages/vinyls.css b/assets/css/pages/vinyls.css new file mode 100644 index 0000000..ecf8b4b --- /dev/null +++ b/assets/css/pages/vinyls.css @@ -0,0 +1,14 @@ +.vinyl-grid{ + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: var(--space-md); + margin-top: var(--space-md); +} + +.vinyl-grid img{ + width: 100%; + height: auto; + border: 1px solid var(--border); + border-radius: var(--r); + background: var(--bg); +} diff --git a/assets/css/site.css b/assets/css/site.css new file mode 100644 index 0000000..4434b60 --- /dev/null +++ b/assets/css/site.css @@ -0,0 +1,891 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2) format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2) format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* greek-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2) format('woff2'); + unicode-range: U+1F00-1FFF; +} +/* greek */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2) format('woff2'); + unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; +} +/* vietnamese */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2) format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2) format('woff2'); + unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url(/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +:root{ + --bg: #ffd; + --ink: #000; + --muted: #333; + --accent: #d22; + --gold: #c69214; + --border: #caa; + --shadow: rgba(0,0,0,.10); + + --wrap: 960px; + --r: 6px; + + /* Unified spacing scale */ + --space-xs: 0.25rem; + --space-sm: 0.5rem; + --space-md: 0.75rem; + --space-lg: 1rem; + --space-xl: 1.35rem; + --space-2xl: 1.75rem; + --space-3xl: 2.5rem; + + /* Typography scale */ + --fs-xs: 0.85rem; + --fs-sm: 0.9rem; + --fs-base: 1rem; + --fs-lg: 1.05rem; + --fs-xl: 1.15rem; + --fs-2xl: 1.5rem; + --fs-3xl: 1.8rem; +} + +/* --- UNIFIED HEADER BUTTONS STYLE --- */ +.header-button { + font-size: var(--fs-sm); + border: 1px solid var(--border); + padding: 4px 8px; + border-radius: var(--r); + color: var(--ink); + text-decoration: none; + background: var(--bg); + cursor: pointer; + font-family: inherit; + display: inline-flex; + align-items: center; + justify-content: center; + transition: background .15s, color .15s, border-color .15s; +} + +.header-button:hover { + background: var(--accent); + color: #000; + border-color: var(--accent); +} + +/* Reset */ +*, *::before, *::after { box-sizing: border-box; } +html, body { height: 100%; } +body { margin: 0; } + +body{ + font-family: "Inter", system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; + line-height: 1.6; + background: var(--bg); + color: var(--ink); + font-size: var(--fs-base); + /* Prevent horizontal scrollbar when menu icon rotates */ + overflow-x: hidden; +} + +/* Typography */ +p{ + margin: var(--space-sm) 0; + line-height: 1.6; +} +p:first-child{ margin-top: 0; } +p:last-child{ margin-bottom: 0; } + +img{ max-width: 100%; height: auto; display: block; } +video{ display: block; } + +/* Accessibility helpers */ +.skip-link{ + position: absolute; + left: -999px; + top: 0; + background: var(--bg); + border: 1px solid var(--border); + padding: .5rem .75rem; + border-radius: var(--r); + z-index: 2000; +} +.skip-link:focus{ left: 1rem; top: 1rem; } + +:focus-visible{ + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* Layout */ +.wrap{ + max-width: var(--wrap); + margin: 0 auto; + padding: var(--space-xl) var(--space-lg) var(--space-3xl); +} + +/* Utilities */ +.stack{ + display: flex; + flex-direction: column; + gap: var(--space-xl); +} + +header.site-header, footer.site-footer{ + background: var(--bg); + border-bottom: 1px solid var(--border); +} + +header.site-header{ + position: sticky; + top: 0; + z-index: 1000; +} + +.header-inner{ + max-width: var(--wrap); + margin: 0 auto; + padding: var(--space-md) var(--space-lg); + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-lg); + flex-wrap: wrap; +} + +.brand{ + display: flex; + align-items: center; + gap: var(--space-md); + min-width: 240px; +} + +.logo{ + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--r); +} +.logo img{ + height: 48px; + width: 48px; + object-fit: contain; + border: 2px solid #000; + border-radius: var(--r); +} + +header.site-header .logo:hover img, +header.site-header .logo:focus-visible img{ + border-color: var(--accent); +} + +.brand-text{ + display: flex; + flex-direction: column; + line-height: 1.2; +} +.brand-text strong{ + font-size: var(--fs-lg); + color: var(--gold); + letter-spacing: .2px; +} +.brand-text span{ + font-size: var(--fs-sm); + color: var(--muted); +} + +.header-controls{ + display: flex; + align-items: center; + gap: var(--space-md); +} + +/* Links (match startpage hover) */ +a{ + color: var(--accent); + text-decoration: none; + transition: 0.1s; +} +a:hover{ + background: var(--accent); + color: #000 !important; +} + +/* Menu */ +.menu-wrapper{ position: relative; } + +#menu-toggle{ + width: 44px; + height: 44px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 22px; + line-height: 1; + transition: transform .25s ease; + border: 1px solid #000; + border-radius: var(--r); + background: var(--bg); + color: var(--ink); + padding: 0; +} + +#menu-toggle:hover { + background: var(--accent); + color: #000; + border-color: #000; +} + +#menu-toggle.active{ + transform: rotate(90deg); + background: var(--bg); + color: var(--ink); + border-color: #000; +} + +#menu-toggle.active:hover{ + background: var(--accent); + color: #000; + border-color: #000; +} + +nav.site-nav{ + position: absolute; + right: 0; + top: calc(100% + var(--space-xs)); + background: var(--bg); + border: 1px solid var(--ink); + border-radius: var(--r); + padding: var(--space-md) var(--space-md); + min-width: 200px; + box-shadow: 0 10px 22px var(--shadow); + z-index: 1200; +} +nav.site-nav ul{ list-style: none; margin: 0; padding: 0; } +nav.site-nav li{ margin: var(--space-sm) 0; } +nav.site-nav a{ + display: block; + padding: var(--space-xs) var(--space-xs); + transition: background .15s, color .15s; + color: var(--ink); +} +nav.site-nav a:hover{ background: var(--accent); color: #000; } + +/* Nav sections */ +nav.site-nav .nav-section{ margin-bottom: var(--space-md); } +nav.site-nav .nav-section:last-child{ margin-bottom: 0; } +nav.site-nav .nav-section + .nav-section{ + border-top: 1px solid var(--border); + padding-top: var(--space-md); +} +nav.site-nav .nav-label{ + font-size: var(--fs-xs); + font-weight: 600; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: var(--space-xs); + padding: var(--space-xs); +} + +/* Language dropdown */ +.lang{ position: relative; } + +.lang-toggle-wrapper{ display: inline-block; } + +.lang-menu{ + position: absolute; + right: 0; + top: calc(100% + var(--space-xs)); + background: var(--bg); + border: 1px solid var(--border); + border-radius: var(--r); + box-shadow: 0 10px 22px var(--shadow); + min-width: 160px; + padding: var(--space-sm); + z-index: 1200; +} +.lang-menu a{ + display: block; + padding: var(--space-sm) var(--space-sm); + color: var(--ink); + transition: background .15s; +} +.lang-menu a:hover{ background: var(--accent); color: #000; } + +/* Sections / cards */ +section{ + margin: var(--space-xl) 0; + border: 1px solid var(--border); + border-radius: var(--r); + padding: var(--space-lg); + background: var(--bg); +} + +h1{ + margin: 0 0 var(--space-md) 0; + color: var(--gold); + font-weight: 700; + font-size: var(--fs-2xl); + letter-spacing: .2px; + line-height: 1.2; +} + +h2{ + margin: 0 0 var(--space-md) 0; + color: var(--gold); + font-size: var(--fs-xl); + font-weight: 700; + letter-spacing: .1px; + line-height: 1.3; +} + +/* CHANGELOG SPECIFIC STYLES */ +.changelog-title{ + color: var(--gold) !important; + margin-bottom: var(--space-sm) !important; +} + +.changelog-date{ + font-size: var(--fs-3xl) !important; + font-weight: 700; + color: var(--muted); + margin: var(--space-sm) 0 var(--space-lg) 0; + line-height: 1.1; +} + +.muted{ color: var(--muted); font-size: var(--fs-sm); } + +/* Video */ +.video-wrap{ margin: var(--space-md) 0 0 0; } +.video-wrap video{ + width: 100%; + height: auto; + max-height: 80vh; + background: #000; + border: 1px solid var(--border); + border-radius: var(--r); +} + +/* Lists */ +.contact-list{ + list-style: none; + padding: 0; + margin: var(--space-md) 0 0 0; +} +.contact-list li{ margin: var(--space-sm) 0; line-height: 1.6; } +.contact-address{ font-style: normal; } + +blockquote{ + margin: var(--space-md) 0 0 0; + padding-left: var(--space-md); + border-left: 3px solid var(--border); + color: var(--muted); + font-style: italic; + font-size: var(--fs-sm); + line-height: 1.6; +} + +/* Iframe loading overlay */ +.iframe-clip{ position: relative; } +.iframe-clip iframe{ position: relative; z-index: 1; } +.iframe-clip.is-loading::before{ + content: "Loading..."; + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + background: rgba(255, 255, 221, 0.92); + color: var(--ink); + font-size: var(--fs-sm); + z-index: 2; +} +.iframe-clip.is-loading::after{ + content: ""; + position: absolute; + width: 22px; + height: 22px; + border: 2px solid var(--border); + border-top-color: var(--accent); + border-radius: 50%; + top: calc(50% + 16px); + left: 50%; + transform: translateX(-50%); + animation: iframe-spin 0.8s linear infinite; + z-index: 3; +} +@keyframes iframe-spin{ + to { transform: translateX(-50%) rotate(360deg); } +} + +/* Friends grid */ +.friends-list{ + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: var(--space-md); + margin: var(--space-md) 0 0 0; + padding: 0; + list-style: none; +} +.friends-list a{ + display: flex; + align-items: center; + justify-content: center; + height: 42px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + + background: var(--bg); + border: 1px solid var(--border); + border-radius: var(--r); + padding: var(--space-sm) var(--space-sm); + color: var(--accent); + transition: background .15s, color .15s, border-color .15s, box-shadow .15s; +} +.friends-list a:hover{ + background: var(--accent); + color: #000; + border-color: var(--accent); + box-shadow: 0 1px 0 var(--accent) inset; +} + +/* Tiles */ +.tile-grid{ + display: grid; + grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); + gap: var(--space-md); + list-style: none; + padding: 0; + margin: var(--space-md) 0 0 0; +} +.tile-grid a{ + display: flex; + align-items: center; + justify-content: center; + height: 64px; + background: var(--bg); + border: 1px solid var(--border); + border-radius: var(--r); + padding: var(--space-sm); + transition: background .15s, border-color .15s, box-shadow .15s; +} +.tile-grid a:hover{ + background: var(--accent); + border-color: var(--accent); + box-shadow: 0 1px 0 var(--accent) inset; +} +.tile-grid img{ width: 100%; height: 100%; object-fit: contain; } + +/* Embeds */ +.embed-frame{ + display: block; + width: 100%; + border: 1px solid var(--border); + border-radius: var(--r); + background: var(--bg); + margin: var(--space-md) 0 0 0; +} +.guestbook-form-frame{ + height: 350px; + min-height: 350px; +} +.iframe-clip{ + --sb: 18px; + overflow: hidden; + border-radius: var(--r); + border: 1px solid var(--border); +} +.iframe-clip > iframe{ + width: calc(100% + var(--sb)); + height: calc(100% + var(--sb)); + border: 0; +} +.guestbook-frame{ min-height: 90vh; } + +#guestbook-comments-iframe { + min-height: 600px; /* Adjusted to show more comments */ +} + +.changelog-frame{ min-height: 360px; } + +/* Audio */ +.audio-wrap{ margin: var(--space-md) 0 0 0; } +audio{ width: 100%; max-width: 400px; } + +/* Blog + changelog lists */ +#blog-list, +#changelog-list{ margin: var(--space-md) 0 0 0; } +#blog-list > div:first-child, +#changelog-list > div:first-child{ margin-bottom: var(--space-md); } +#blog-list ol, +#changelog-list ol{ margin: var(--space-md) 0 0 0; padding-left: var(--space-xl); } +#blog-list li, +#changelog-list li{ margin: 0 0 var(--space-md) 0; line-height: 1.6; } +#blog-list .muted, +#changelog-list .muted{ font-size: var(--fs-sm); margin-top: var(--space-xs); } +#blog-list .blog-more{ margin-top: var(--space-xs); } +#changelog-list .changelog-body{ margin-top: var(--space-xs); white-space: pre-line; } +#changelog-list time{ color: var(--accent); } + +/* Footer */ +footer.site-footer{ border-top: 1px solid var(--border); border-bottom: none; } +.footer-inner{ + max-width: var(--wrap); + margin: 0 auto; + padding: var(--space-lg) var(--space-lg) var(--space-2xl); + color: var(--muted); + font-size: var(--fs-sm); + line-height: 1.6; +} +.badge{ + display: inline-flex; + margin-top: var(--space-sm); + border-radius: var(--r); + padding: var(--space-xs); + border: 1px solid var(--border); + background: var(--bg); + transition: border-color .15s; +} +.badge:hover{ border-color: var(--accent); } + +/* Reset Button */ +.reset-button{ + font-size: var(--fs-sm); + border: 1px solid #000; /* Black border */ + padding: 4px 8px; + border-radius: var(--r); + color: #000; /* Black text */ + background: #ffd; /* Light yellow background */ + cursor: pointer; + font-family: inherit; + display: inline-flex; + align-items: center; + justify-content: center; + transition: background .15s, color .15s, border-color .15s; +} + +.reset-button:hover { + background: var(--accent); /* Dark red on hover */ + color: #000; /* Black text on hover */ + border-color: #000; /* Black border on hover */ +} + +@media (max-width: 600px){ + .tile-grid{ + display: flex; + flex-direction: column; + align-items: center; + } + .tile-grid li{ + margin-bottom: 1rem; + text-align: center; + } + .contact-list{ + padding-left: 20px; + } + .friends-list{ + display: flex; + flex-direction: column; + gap: 10px; + } +} + +@media (max-width: 520px){ + header.site-header{ position: sticky; } + .header-inner{ position: relative; } + nav.site-nav{ + min-width: 200px; + max-width: calc(100vw - 2 * var(--space-lg)); + } + .lang-menu{ + right: auto; + left: 0; + max-width: calc(100vw - 32px); + } + #menu-toggle{ display: inline-flex; transition: transform .25s ease; } + #menu-toggle.active{ transform: rotate(90deg); } +} + +@media (prefers-reduced-motion: reduce){ + *{ transition: none !important; scroll-behavior: auto !important; } + #menu-toggle.active{ transform: none; } +} + +/* From style.css */ +h1 { + font-family: 'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; + font-size: 1.875rem; /* 30px / 16px (base font size) */ + padding-left: 40px; +} + +pre { + font-family: 'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; + font-size: 12px; + padding-left: 40px; +} + +.button1 { + background-color: black; + font-family: Comic Sans MS; + font-weight: 300; +} + +.member { + float: left; + width: calc(20% - 2%); /* Adjust width to account for margins */ + margin: 1% 1% 45px 1%; +} + +.name { + bottom: 0px; +} + +.member img { + width: 50%; + display: block; +} + +ul.flowxl { + display: flex; + flex-wrap: wrap; + padding: 0; +} + +ul.flowxl > li { + list-style-type: none; + text-align: center; + width: var(--xiconsize); + min-width: var(--xiconsize); + max-width: var(--xiconsize); + max-height: calc(var(--xiconsize) + 60px); + padding: 2px; + margin: 0.125rem; /* Use rem for margin */ + overflow: hidden; + font-size: 1rem; + line-height: 1; +} + +ul.flowxl > li > a { + display: block; + line-height: 1; + font-size: 1.2rem; +} + +ul.flowxl li > a > img, +ul.flowxl li > img { + display: block; + border-radius: 9px; + width: auto; + max-width: var(--xiconsize); + max-height: var(--xiconsize); + overflow: hidden; + margin-left: auto; + margin-right: auto; +} + +ul.flowxl li > a > img[src$=".svg"] { + max-width: 170px; + max-height: 170px; +} + +.country-img { + height: 12.5rem; /* Use rem units for height */ + width: 250px; /* Desired width */ + object-fit: contain; /* Scales image to fit within the box while maintaining aspect ratio */ + max-width: 100%; /* Ensures responsiveness */ +} + +.countries { + flex-wrap: wrap; /* Ensures images wrap if they exceed container width */ + gap: 10px; /* Adds spacing between images */ + justify-content: center; /* Centers the images horizontally */ +} + +.vpn-logo { + width: 200px; /* Set max-width for scaling */ + max-width: 100%; /* Responsive width */ + height: auto; /* Maintain aspect ratio */ + object-fit: contain; /* Handle scaling gracefully */ +} + +.toesu-logo { + width: 200px; /* Set the default width */ + max-width: 100%; /* Ensure image scales on smaller screens */ + height: auto; /* Maintain original aspect ratio */ + object-fit: contain; /* Gracefully handle image scaling */ +} + +@import url('https://fonts.googleapis.com/css2?family=Anonymous+Pro:ital,wght@0,400;0,700;1,400;1,700&display=swap'); + + diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2 Binary files differnew file mode 100644 index 0000000..d750914 --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2 diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2 Binary files differnew file mode 100644 index 0000000..d15208d --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2 diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2 Binary files differnew file mode 100644 index 0000000..024f077 --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2 diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2 Binary files differnew file mode 100644 index 0000000..479d010 --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2 diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2 Binary files differnew file mode 100644 index 0000000..de83a9c --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2 diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2 Binary files differnew file mode 100644 index 0000000..6e7141f --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2 diff --git a/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2 b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2 Binary files differnew file mode 100644 index 0000000..a40c469 --- /dev/null +++ b/assets/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2 diff --git a/assets/js/includes.js b/assets/js/includes.js new file mode 100644 index 0000000..4af99f4 --- /dev/null +++ b/assets/js/includes.js @@ -0,0 +1,32 @@ +(async function () { + async function loadInto(selector, url) { + const mount = document.querySelector(selector); + if (!mount) return; + + try { + const res = await fetch(url); + if (!res.ok) throw new Error("HTTP " + res.status); + const html = await res.text(); + mount.innerHTML = html; + } catch (e) { + // Fail open: if includes fail, keep page usable. + // Intentionally no console noise. + } + } + + // Pages opt-in by including: <div data-include="header"></div> + // and/or <div data-include="footer"></div> + await Promise.all([ + loadInto('[data-include="header"]', "/partials/header.html"), + loadInto('[data-include="footer"]', "/partials/footer.html"), + ]); + + // If a page uses includes, it likely removed the built-in header/footer. + // Re-run site.js behaviors after injection. + if (document.querySelector('[data-include="header"], [data-include="footer"]')) { + const s = document.createElement("script"); + s.src = "/assets/js/site.js"; + s.defer = true; + document.head.appendChild(s); + } +})(); diff --git a/assets/js/pages/404.js b/assets/js/pages/404.js new file mode 100644 index 0000000..a97a5b1 --- /dev/null +++ b/assets/js/pages/404.js @@ -0,0 +1,5 @@ +(function(){ + var el = document.getElementById('y'); + if (!el) return; + el.textContent = String(new Date().getFullYear()); + })(); diff --git a/assets/js/pages/50x.js b/assets/js/pages/50x.js new file mode 100644 index 0000000..a97a5b1 --- /dev/null +++ b/assets/js/pages/50x.js @@ -0,0 +1,5 @@ +(function(){ + var el = document.getElementById('y'); + if (!el) return; + el.textContent = String(new Date().getFullYear()); + })(); diff --git a/assets/js/pages/guestbook_jp.js b/assets/js/pages/guestbook_jp.js new file mode 100644 index 0000000..5f3a055 --- /dev/null +++ b/assets/js/pages/guestbook_jp.js @@ -0,0 +1,91 @@ +document.addEventListener("DOMContentLoaded", function () { + const form = document.getElementById("guestbook-form"); + const entriesContainer = document.getElementById("guestbook-entries"); + const captchaCanvas = document.getElementById("captcha-canvas"); + const refreshCaptchaButton = document.getElementById("refresh-captcha"); + const captchaInput = document.getElementById("captcha-input"); + const GUESTBOOK_KEY = "guestbookEntries"; + + let currentCaptcha = ""; + + function generateCaptcha() { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let captcha = ""; + for (let i = 0; i < 6; i++) captcha += chars.charAt(Math.floor(Math.random() * chars.length)); + return captcha; + } + + function drawCaptcha(captcha) { + const ctx = captchaCanvas.getContext("2d"); + ctx.clearRect(0, 0, captchaCanvas.width, captchaCanvas.height); + ctx.font = "22px Arial"; + ctx.fillStyle = "#000"; + ctx.fillText(captcha, 10, 32); + } + + function refreshCaptcha() { + currentCaptcha = generateCaptcha(); + drawCaptcha(currentCaptcha); + } + + function formatMessage(message) { + return message + .split("\n") + .map((line) => { + if (line.startsWith(">")) return `<span class="anonymous">${line}</span>`; + return line; + }) + .join("<br>"); + } + + function loadEntries() { + const entries = JSON.parse(localStorage.getItem(GUESTBOOK_KEY)) || []; + entriesContainer.innerHTML = ""; + + entries + .slice() + .reverse() + .forEach((entry) => { + const entryElement = document.createElement("div"); + entryElement.className = "entry"; + + const nameElement = document.createElement("h4"); + if (entry.name === "Anonymous") nameElement.className = "anonymous"; + nameElement.textContent = entry.name; + entryElement.appendChild(nameElement); + + const messageElement = document.createElement("p"); + messageElement.innerHTML = formatMessage(entry.message); + entryElement.appendChild(messageElement); + + entriesContainer.appendChild(entryElement); + }); + } + + form.addEventListener("submit", function (event) { + event.preventDefault(); + + let name = document.getElementById("name").value.trim(); + if (!name) name = "Anonymous"; + + const message = document.getElementById("message").value.trim(); + const captchaValue = captchaInput.value.trim(); + + if (name && message && captchaValue === currentCaptcha) { + const entries = JSON.parse(localStorage.getItem(GUESTBOOK_KEY)) || []; + entries.push({ name, message }); + localStorage.setItem(GUESTBOOK_KEY, JSON.stringify(entries)); + + form.reset(); + document.getElementById("name").value = "Anonymous"; + loadEntries(); + refreshCaptcha(); + } else { + alert("CAPTCHA is incorrect. Please try again."); + } + }); + + refreshCaptcha(); + refreshCaptchaButton.addEventListener("click", refreshCaptcha); + loadEntries(); + }); diff --git a/assets/js/pages/guestbook_zh.js b/assets/js/pages/guestbook_zh.js new file mode 100644 index 0000000..5f3a055 --- /dev/null +++ b/assets/js/pages/guestbook_zh.js @@ -0,0 +1,91 @@ +document.addEventListener("DOMContentLoaded", function () { + const form = document.getElementById("guestbook-form"); + const entriesContainer = document.getElementById("guestbook-entries"); + const captchaCanvas = document.getElementById("captcha-canvas"); + const refreshCaptchaButton = document.getElementById("refresh-captcha"); + const captchaInput = document.getElementById("captcha-input"); + const GUESTBOOK_KEY = "guestbookEntries"; + + let currentCaptcha = ""; + + function generateCaptcha() { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let captcha = ""; + for (let i = 0; i < 6; i++) captcha += chars.charAt(Math.floor(Math.random() * chars.length)); + return captcha; + } + + function drawCaptcha(captcha) { + const ctx = captchaCanvas.getContext("2d"); + ctx.clearRect(0, 0, captchaCanvas.width, captchaCanvas.height); + ctx.font = "22px Arial"; + ctx.fillStyle = "#000"; + ctx.fillText(captcha, 10, 32); + } + + function refreshCaptcha() { + currentCaptcha = generateCaptcha(); + drawCaptcha(currentCaptcha); + } + + function formatMessage(message) { + return message + .split("\n") + .map((line) => { + if (line.startsWith(">")) return `<span class="anonymous">${line}</span>`; + return line; + }) + .join("<br>"); + } + + function loadEntries() { + const entries = JSON.parse(localStorage.getItem(GUESTBOOK_KEY)) || []; + entriesContainer.innerHTML = ""; + + entries + .slice() + .reverse() + .forEach((entry) => { + const entryElement = document.createElement("div"); + entryElement.className = "entry"; + + const nameElement = document.createElement("h4"); + if (entry.name === "Anonymous") nameElement.className = "anonymous"; + nameElement.textContent = entry.name; + entryElement.appendChild(nameElement); + + const messageElement = document.createElement("p"); + messageElement.innerHTML = formatMessage(entry.message); + entryElement.appendChild(messageElement); + + entriesContainer.appendChild(entryElement); + }); + } + + form.addEventListener("submit", function (event) { + event.preventDefault(); + + let name = document.getElementById("name").value.trim(); + if (!name) name = "Anonymous"; + + const message = document.getElementById("message").value.trim(); + const captchaValue = captchaInput.value.trim(); + + if (name && message && captchaValue === currentCaptcha) { + const entries = JSON.parse(localStorage.getItem(GUESTBOOK_KEY)) || []; + entries.push({ name, message }); + localStorage.setItem(GUESTBOOK_KEY, JSON.stringify(entries)); + + form.reset(); + document.getElementById("name").value = "Anonymous"; + loadEntries(); + refreshCaptcha(); + } else { + alert("CAPTCHA is incorrect. Please try again."); + } + }); + + refreshCaptcha(); + refreshCaptchaButton.addEventListener("click", refreshCaptcha); + loadEntries(); + }); diff --git a/assets/js/pages/hitcounter.js b/assets/js/pages/hitcounter.js new file mode 100644 index 0000000..9c3f888 --- /dev/null +++ b/assets/js/pages/hitcounter.js @@ -0,0 +1,16 @@ +function countUniqueVisitors() { + const VISITOR_KEY = "uniqueVisitorCount"; + let visitorCount = localStorage.getItem(VISITOR_KEY); + if (!visitorCount) visitorCount = 0; + + const hasVisited = sessionStorage.getItem("hasVisited"); + if (!hasVisited) { + visitorCount++; + localStorage.setItem(VISITOR_KEY, visitorCount); + sessionStorage.setItem("hasVisited", "true"); + } + + document.getElementById("visitor-counter").innerText = visitorCount; + } + + countUniqueVisitors(); diff --git a/assets/js/pages/hitcounter_jp.js b/assets/js/pages/hitcounter_jp.js new file mode 100644 index 0000000..9c3f888 --- /dev/null +++ b/assets/js/pages/hitcounter_jp.js @@ -0,0 +1,16 @@ +function countUniqueVisitors() { + const VISITOR_KEY = "uniqueVisitorCount"; + let visitorCount = localStorage.getItem(VISITOR_KEY); + if (!visitorCount) visitorCount = 0; + + const hasVisited = sessionStorage.getItem("hasVisited"); + if (!hasVisited) { + visitorCount++; + localStorage.setItem(VISITOR_KEY, visitorCount); + sessionStorage.setItem("hasVisited", "true"); + } + + document.getElementById("visitor-counter").innerText = visitorCount; + } + + countUniqueVisitors(); diff --git a/assets/js/pages/hitcounter_zh.js b/assets/js/pages/hitcounter_zh.js new file mode 100644 index 0000000..9c3f888 --- /dev/null +++ b/assets/js/pages/hitcounter_zh.js @@ -0,0 +1,16 @@ +function countUniqueVisitors() { + const VISITOR_KEY = "uniqueVisitorCount"; + let visitorCount = localStorage.getItem(VISITOR_KEY); + if (!visitorCount) visitorCount = 0; + + const hasVisited = sessionStorage.getItem("hasVisited"); + if (!hasVisited) { + visitorCount++; + localStorage.setItem(VISITOR_KEY, visitorCount); + sessionStorage.setItem("hasVisited", "true"); + } + + document.getElementById("visitor-counter").innerText = visitorCount; + } + + countUniqueVisitors(); diff --git a/assets/js/pages/mstartpage-index.js b/assets/js/pages/mstartpage-index.js new file mode 100644 index 0000000..db518ab --- /dev/null +++ b/assets/js/pages/mstartpage-index.js @@ -0,0 +1,118 @@ +// Date and time functionality + function updateDateRealtime() { + const dateElement = document.getElementById("realtime-date"); + const clockElement = document.getElementById("realtime-clock"); + + const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + const months = ["January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December"]; + + const now = new Date(); + + // Date parts + const dayName = days[now.getDay()]; + const month = months[now.getMonth()]; + const dayNumber = now.getDate(); + const year = now.getFullYear(); + + const ordinal = (dayNumber > 3 && dayNumber < 21) ? 'th' : + (dayNumber % 10 === 1) ? 'st' : + (dayNumber % 10 === 2) ? 'nd' : + (dayNumber % 10 === 3) ? 'rd' : 'th'; + + dateElement.textContent = `${dayName}, ${month} ${dayNumber}${ordinal}, ${year}.`; + + // Clock parts (12-hour format) + let hours = now.getHours(); + const minutes = now.getMinutes(); + const seconds = now.getSeconds(); + + const period = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12 || 12; + + const formattedHours = hours.toString().padStart(2, "0"); + const formattedMinutes = minutes.toString().padStart(2, "0"); + const formattedSeconds = seconds.toString().padStart(2, "0"); + + clockElement.textContent = `${formattedHours}:${formattedMinutes}:${formattedSeconds} ${period}`; + } + + updateDateRealtime(); + setInterval(updateDateRealtime, 1000); + + // Menu toggle functionality + document.getElementById('menu-toggle').addEventListener('click', function() { + const menu = document.getElementById('main-menu'); + menu.classList.toggle('show'); + }); + + // Collapsible sections + const collapsibles = document.getElementsByClassName("collapsible"); + + for (let i = 0; i < collapsibles.length; i++) { + collapsibles[i].addEventListener("click", function() { + this.classList.toggle("active"); + const content = this.nextElementSibling; + if (content.style.display === "block") { + content.style.display = "none"; + } else { + content.style.display = "block"; + } + }); + } + + // XXX Verification functionality + const xxxToggle = document.getElementById('xxx-toggle'); + const xxxModal = document.getElementById('xxx-modal'); + const xxxConfirm = document.getElementById('xxx-confirm'); + const xxxDeny = document.getElementById('xxx-deny'); + const xxxList = document.getElementById('xxx-list'); + + // Check if already verified + let isVerified = localStorage.getItem('xxx-verified') === 'true'; + let isContentVisible = localStorage.getItem('xxx-visible') === 'true'; + + // Initialize based on stored state + if (isVerified && isContentVisible) { + xxxToggle.textContent = 'Hide XXX Content'; + xxxList.style.display = 'block'; + } else if (isVerified && !isContentVisible) { + xxxToggle.textContent = 'Show XXX Content'; + xxxList.style.display = 'none'; + } + + xxxToggle.addEventListener('click', function() { + if (isVerified) { + // Toggle visibility if already verified + if (xxxList.style.display === 'block') { + // Hide the content + xxxList.style.display = 'none'; + xxxToggle.textContent = 'Show XXX Content'; + localStorage.setItem('xxx-visible', 'false'); + } else { + // Show the content + xxxList.style.display = 'block'; + xxxToggle.textContent = 'Hide XXX Content'; + localStorage.setItem('xxx-visible', 'true'); + } + } else { + // Show verification modal if not verified + xxxModal.style.display = 'flex'; + } + }); + + xxxConfirm.addEventListener('click', function() { + // Set verification status + isVerified = true; + localStorage.setItem('xxx-verified', 'true'); + localStorage.setItem('xxx-visible', 'true'); + + // Hide modal and show content + xxxModal.style.display = 'none'; + xxxList.style.display = 'block'; + xxxToggle.textContent = 'Hide XXX Content'; + }); + + xxxDeny.addEventListener('click', function() { + xxxModal.style.display = 'none'; + }); diff --git a/assets/js/pages/test.js b/assets/js/pages/test.js new file mode 100644 index 0000000..ee1c831 --- /dev/null +++ b/assets/js/pages/test.js @@ -0,0 +1,10 @@ +document.getElementById("lastmod").textContent = document.lastModified; + +document.getElementById("menu-toggle").addEventListener("click", function() { + const sidebar = document.getElementById("mobile-sidebar"); + sidebar.classList.toggle("visible"); + if (sidebar.classList.contains("visible")) { + sidebar.scrollTop = 0; + window.scrollTo(0, 0); + } + }); diff --git a/assets/js/pages/test_jp.js b/assets/js/pages/test_jp.js new file mode 100644 index 0000000..ee1c831 --- /dev/null +++ b/assets/js/pages/test_jp.js @@ -0,0 +1,10 @@ +document.getElementById("lastmod").textContent = document.lastModified; + +document.getElementById("menu-toggle").addEventListener("click", function() { + const sidebar = document.getElementById("mobile-sidebar"); + sidebar.classList.toggle("visible"); + if (sidebar.classList.contains("visible")) { + sidebar.scrollTop = 0; + window.scrollTo(0, 0); + } + }); diff --git a/assets/js/pages/test_zh.js b/assets/js/pages/test_zh.js new file mode 100644 index 0000000..ee1c831 --- /dev/null +++ b/assets/js/pages/test_zh.js @@ -0,0 +1,10 @@ +document.getElementById("lastmod").textContent = document.lastModified; + +document.getElementById("menu-toggle").addEventListener("click", function() { + const sidebar = document.getElementById("mobile-sidebar"); + sidebar.classList.toggle("visible"); + if (sidebar.classList.contains("visible")) { + sidebar.scrollTop = 0; + window.scrollTo(0, 0); + } + }); diff --git a/assets/js/site.js b/assets/js/site.js new file mode 100644 index 0000000..39891b7 --- /dev/null +++ b/assets/js/site.js @@ -0,0 +1,415 @@ +(function () { + function byId(id) { + return document.getElementById(id); + } + + const menuBtn = byId("menu-toggle"); + const nav = byId("site-nav"); + + const langToggle = byId("lang-toggle"); + const langMenu = byId("lang-options"); + const currentLang = byId("current-lang"); + + let openDropdown = null; + + function closeMenu() { + if (!menuBtn || !nav) return; + menuBtn.classList.remove("active"); + menuBtn.setAttribute("aria-expanded", "false"); + nav.hidden = true; + if (openDropdown === "menu") openDropdown = null; + } + + function closeLang() { + if (!langToggle || !langMenu) return; + langToggle.setAttribute("aria-expanded", "false"); + langMenu.hidden = true; + if (openDropdown === "lang") openDropdown = null; + } + + function toggleMenu(e) { + if (!menuBtn || !nav) return; + e.stopPropagation(); + + if (openDropdown === "lang") closeLang(); + + const open = menuBtn.getAttribute("aria-expanded") === "true"; + if (open) { + closeMenu(); + return; + } + + menuBtn.classList.add("active"); + menuBtn.setAttribute("aria-expanded", "true"); + nav.hidden = false; + openDropdown = "menu"; + } + + function toggleLang(e) { + if (!langToggle || !langMenu) return; + e.stopPropagation(); + + if (openDropdown === "menu") closeMenu(); + + const open = langToggle.getAttribute("aria-expanded") === "true"; + if (open) { + closeLang(); + return; + } + + langToggle.setAttribute("aria-expanded", "true"); + langMenu.hidden = false; + openDropdown = "lang"; + } + + if (nav) nav.hidden = true; + if (langMenu) langMenu.hidden = true; + + if (menuBtn && nav) { + menuBtn.addEventListener("click", toggleMenu); + nav.addEventListener("click", (e) => e.stopPropagation()); + } + + if (langToggle && langMenu) { + langToggle.addEventListener("click", toggleLang); + langMenu.addEventListener("click", (e) => e.stopPropagation()); + } + + if ((menuBtn && nav) || (langToggle && langMenu)) { + document.addEventListener("click", function (e) { + if ( + menuBtn && nav && + (menuBtn.contains(e.target) || nav.contains(e.target)) + ) { + return; + } + if ( + langToggle && langMenu && + (langToggle.contains(e.target) || langMenu.contains(e.target)) + ) { + return; + } + closeMenu(); + closeLang(); + }); + + document.addEventListener("keydown", function (e) { + if (e.key === "Escape") { + closeMenu(); + closeLang(); + } + }); + } + + if (currentLang) { + const docLang = (document.documentElement.lang || "en").toLowerCase(); + currentLang.textContent = docLang === "zh" ? "ZH" : docLang === "ja" ? "JA" : "EN"; + } + + if (langMenu) { + langMenu.querySelectorAll("a[data-lang]").forEach((a) => { + a.addEventListener("click", function () { + localStorage.setItem("preferredLang", this.getAttribute("data-lang") || "en"); + }); + }); + } + + // Language menu hrefs: convert current page to *_zh.html / *_jp.html. + // Needs to work for both: + // - directory URLs: /foo/ (serve /foo/index.html) + // - file URLs: /foo/page.html + function updateLangMenuHrefs() { + const links = document.querySelectorAll("a[data-lang-href][data-lang]"); + if (!links.length) return; + + let path = window.location.pathname || "/"; + if (!path.startsWith("/")) path = "/" + path; + + const isDir = path.endsWith("/"); + const file = isDir ? "index.html" : (path.split("/").pop() || "index.html"); + const base = isDir ? path : path.slice(0, -file.length); + + const baseName = file.replace(/_(zh|jp)\.html$/i, ".html"); + const map = { + en: baseName, + zh: baseName.replace(/(_(zh|jp))?\.html$/i, "_zh.html"), + ja: baseName.replace(/(_(zh|jp))?\.html$/i, "_jp.html"), + }; + + links.forEach((a) => { + const lang = (a.getAttribute("data-lang") || "en").toLowerCase(); + const targetFile = map[lang] || map.en; + a.href = base + targetFile; + }); + } + + function updateAriaCurrent() { + const path = window.location.pathname || "/"; + const normalized = path.startsWith("/") ? path : "/" + path; + const isDir = normalized.endsWith("/"); + const file = isDir ? "index.html" : (normalized.split("/").pop() || "index.html"); + const base = isDir ? normalized : normalized.slice(0, -file.length); + const indexPath = base + "index.html"; + const dirPath = base || "/"; + const candidates = new Set([normalized, indexPath, dirPath, dirPath.replace(/\/$/, "")]); + + document.querySelectorAll("#site-nav a[href]").forEach((a) => { + const href = a.getAttribute("href") || ""; + const hrefUrl = new URL(href, window.location.origin); + if (hrefUrl.origin !== window.location.origin) { + a.removeAttribute("aria-current"); + return; + } + const hrefPath = hrefUrl.pathname; + if (candidates.has(hrefPath)) { + a.setAttribute("aria-current", "page"); + } else { + a.removeAttribute("aria-current"); + } + }); + + const docLang = (document.documentElement.lang || "en").toLowerCase(); + document.querySelectorAll("#lang-options a[data-lang]").forEach((a) => { + const lang = (a.getAttribute("data-lang") || "en").toLowerCase(); + if (lang === docLang) { + a.setAttribute("aria-current", "page"); + } else { + a.removeAttribute("aria-current"); + } + }); + } + + // Run once now... + updateLangMenuHrefs(); + updateAriaCurrent(); + // ...and again after layout/injection settles. + setTimeout(updateLangMenuHrefs, 0); + setTimeout(updateAriaCurrent, 0); + + // Home page blog list (optional) + const blogList = byId("blog-list"); + if (blogList) { + const blogHost = "https://blog.sillylaird.ca"; + const ctrl = new AbortController(); + const timeout = setTimeout(() => ctrl.abort(), 3500); + + fetch(blogHost + "/api/posts.php", { signal: ctrl.signal }) + .then((r) => r.json()) + .then((posts) => { + blogList.textContent = ""; + + const top = document.createElement("div"); + + const strong = document.createElement("strong"); + strong.textContent = "Posts"; + top.appendChild(strong); + + top.appendChild(document.createTextNode(" (")); + const allLink = document.createElement("a"); + allLink.href = blogHost; + allLink.textContent = "all"; + top.appendChild(allLink); + top.appendChild(document.createTextNode(")")); + + blogList.appendChild(top); + + const list = document.createElement("ol"); + (posts || []).forEach((post) => { + const li = document.createElement("li"); + + const a = document.createElement("a"); + a.href = blogHost + "/" + String(post.path || "").replace(/^\/+/, ""); + a.textContent = String(post.title || "Untitled"); + + const date = document.createElement("div"); + date.className = "muted"; + + const y = String(post.year || ""); + const m = String(post.month || "").padStart(2, "0"); + const d = String(post.day || "").padStart(2, "0"); + const iso = y && m && d ? `${y}-${m}-${d}` : ""; + + const time = document.createElement("time"); + if (iso) time.setAttribute("datetime", iso); + time.textContent = iso || ""; + + li.appendChild(a); + li.appendChild(document.createElement("br")); + date.appendChild(time); + li.appendChild(date); + + list.appendChild(li); + }); + + blogList.appendChild(list); + + if (!list.children.length) { + const empty = document.createElement("div"); + empty.className = "muted"; + empty.textContent = "No posts yet."; + blogList.appendChild(empty); + } + }) + .catch((err) => { + blogList.textContent = err && err.name === "AbortError" + ? "Blog list timed out." + : "Cannot load posts right now."; + }) + .finally(() => clearTimeout(timeout)); + } + + const changelogList = byId("changelog-list"); + if (changelogList) { + const changelogPage = "/changelog/"; + const ctrl = new AbortController(); + const timeout = setTimeout(() => ctrl.abort(), 3500); + + fetch(changelogPage, { signal: ctrl.signal }) + .then((r) => r.text()) + .then((html) => { + changelogList.textContent = ""; + const doc = new DOMParser().parseFromString(html, "text/html"); + const entries = Array.from(doc.querySelectorAll(".changelog-entry")); + + const top = document.createElement("div"); + + const strong = document.createElement("strong"); + strong.textContent = "Entries"; + top.appendChild(strong); + + top.appendChild(document.createTextNode(" (")); + const allLink = document.createElement("a"); + allLink.href = "/changelog/"; + allLink.textContent = "all"; + top.appendChild(allLink); + top.appendChild(document.createTextNode(")")); + + changelogList.appendChild(top); + + const list = document.createElement("ol"); + entries.forEach((entry) => { + const li = document.createElement("li"); + + const titleText = (entry.querySelector("strong, b")?.textContent || "").trim(); + const timeEl = entry.querySelector("time"); + const dateText = (timeEl?.textContent || "").trim(); + const dateIso = (timeEl?.getAttribute("datetime") || "").trim(); + const bodyEl = entry.querySelector(".text"); + const bodyText = (bodyEl?.textContent || "").trim(); + + const title = document.createElement("strong"); + if (titleText) { + title.textContent = titleText; + li.appendChild(title); + + if (dateText) { + const date = document.createElement("div"); + date.className = "muted"; + const time = document.createElement("time"); + if (dateIso) time.setAttribute("datetime", dateIso); + time.textContent = dateText; + date.appendChild(time); + li.appendChild(date); + } + } else if (dateText) { + title.textContent = dateText; + li.appendChild(title); + } + + if (bodyText) { + const body = document.createElement("div"); + body.className = "changelog-body"; + body.textContent = bodyText; + li.appendChild(body); + } + + list.appendChild(li); + }); + + changelogList.appendChild(list); + + if (!list.children.length) { + const empty = document.createElement("div"); + empty.className = "muted"; + empty.textContent = "No updates yet."; + changelogList.appendChild(empty); + } + }) + .catch((err) => { + changelogList.textContent = err && err.name === "AbortError" + ? "Changelog list timed out." + : "Cannot load changelog right now."; + }) + .finally(() => clearTimeout(timeout)); + } + + const resetBtn = byId("guestbook-reset"); + if (resetBtn) { + resetBtn.addEventListener("click", () => { + const frame = byId("guestbook-form-iframe"); + if (!frame) return; + setIframeLoading(frame); + const src = frame.getAttribute("src") || frame.src; + if (src) { + // Reset by reloading the iframe URL (works cross-origin too). + frame.setAttribute("src", src); + return; + } + if (frame.contentWindow) frame.contentWindow.location.reload(); + }); + } + + function setIframeLoading(frame) { + if (!frame) return; + const clip = frame.closest(".iframe-clip"); + if (!clip) return; + clip.classList.add("is-loading"); + const onLoad = () => { + clip.classList.remove("is-loading"); + }; + frame.addEventListener("load", onLoad, { once: true }); + } + + function resetIframe(frame) { + if (!frame) return; + const src = frame.getAttribute("src") || frame.src; + if (src) { + frame.setAttribute("src", src); + return; + } + if (frame.contentWindow) frame.contentWindow.location.reload(); + } + + document.querySelectorAll("button[data-reset-iframe]").forEach((btn) => { + btn.addEventListener("click", () => { + const key = btn.getAttribute("data-reset-iframe"); + if (!key) return; + const scope = btn.closest(".iframe-clip") || btn.parentElement || document; + const frame = scope.querySelector(`iframe[data-iframe=\"${key}\"]`) || document.querySelector(`iframe[data-iframe=\"${key}\"]`); + setIframeLoading(frame); + resetIframe(frame); + }); + }); + + // Footer year: local time only. + (function () { + const el = byId("copyright-year"); + if (!el) return; + + el.textContent = String(new Date().getFullYear()); + })(); + + // Footer last-updated: based on document.lastModified. + (function () { + const el = byId("last-updated"); + if (!el) return; + + const raw = document.lastModified; + const date = raw ? new Date(raw) : null; + if (!date || Number.isNaN(date.getTime())) return; + + const iso = date.toISOString().slice(0, 10); + el.setAttribute("datetime", iso); + el.textContent = iso; + })(); +})(); |
