diff --git a/README.md b/README.md index 80e2bda..592ab77 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ This repository contains the documentation for the MeowBox project. +## Docs documents + +Documents are located in the `docs/markdown` directory. + ## Contributing Contributions are welcome! Please read the [contribution guidelines](CONTRIBUTING.md) before submitting a pull request. diff --git a/docs/404.html b/docs/404.html index 57db2e9..7219871 100644 --- a/docs/404.html +++ b/docs/404.html @@ -1 +1,25 @@ -404 \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/css/404.css b/docs/css/404.css new file mode 100644 index 0000000..226d17f --- /dev/null +++ b/docs/css/404.css @@ -0,0 +1,134 @@ +.container-404 { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 80%; + height: 80%; + border-radius: 20px; + backdrop-filter: blur(3px); + background-color: rgba(255, 255, 255, 0.2); + box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.2); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.container-404 i { + position: absolute; + font-size: 256px; + color: #000; + left: 32px; + animation: rotate 2s linear infinite; +} + +@keyframes rotate { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} + +.right-container-404 { + position: absolute; + width: calc(100% - 416px); + right: 32px; + text-align: center; +} + +.right-container-404 h1, +.right-container-404 p { + padding: 8px; +} + +.go-home-button { + height: 48px; + width: 210px; + align-items: center; + justify-content: center; + position: relative; + border: 0.1px solid rgba(255, 255, 255, 0.2); + border-radius: 16px; + backdrop-filter: blur(3px); + background-color: rgba(255, 255, 255, 0.2); + cursor: pointer; +} + +.go-home-button i { + font-size: 18px; + left: 12px; + bottom: 14px; + animation: none; +} + +.go-home-button .go-home-button-text { + position: absolute; + right: 12px; + bottom: 11px; + font-size: 18px; +} + +.go-home-button:hover { + background-color: rgba(255, 255, 255, 0.4); +} + +.go-home-button:active { + background-color: rgba(255, 255, 255, 0.6); +} + +.lang-select-404 { + margin-top: 8px; + width: 100%; +} + +.lang-select-404 select { + outline: none; + border: none; + text-indent: 0.01px; + text-overflow: ''; + backdrop-filter: blur(3px); + background: rgba(255, 255, 255, 0.2); + border-radius: 8px; + overflow: hidden; + cursor: pointer; + padding: 4px 24px 12px 10px; + width: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + text-indent: 0.01px; + text-overflow: ''; + background-image: none; + position: relative; + z-index: 1; +} + +.lang-select-404 select::-ms-expand { + display: none; +} + +.lang-select-404::after { + content: "\f1ab"; + font-family: "Font Awesome 7 Free"; + font-weight: 900; + position: absolute; + transform: translateY(-50%); + font-size: 20px; + color: #000; + pointer-events: none; + margin-top: 16px; + margin-left: -28px; + z-index: 1; +} + +.lang-select-404 select:hover { + background-color: rgba(255, 255, 255, 0.4); +} + +.lang-select-404 select:active { + background-color: rgba(255, 255, 255, 0.6); +} \ No newline at end of file diff --git a/docs/css/layout.css b/docs/css/layout.css new file mode 100644 index 0000000..609c82a --- /dev/null +++ b/docs/css/layout.css @@ -0,0 +1,13 @@ +/* Global styles */ +html, +body { + margin: 0; + padding: 0; + overflow: hidden; +} + +/* Main styles */ +#page { + height: 100vh; + overflow: hidden; +} \ No newline at end of file diff --git a/docs/img/background_v0.0.x.webp b/docs/img/background_v0.0.x.webp new file mode 100644 index 0000000..6124d9d Binary files /dev/null and b/docs/img/background_v0.0.x.webp differ diff --git a/docs/img/background_v0.1.x.webp b/docs/img/background_v0.1.x.webp new file mode 100644 index 0000000..62f0ec4 Binary files /dev/null and b/docs/img/background_v0.1.x.webp differ diff --git a/docs/js/404.js b/docs/js/404.js new file mode 100644 index 0000000..dadaefd --- /dev/null +++ b/docs/js/404.js @@ -0,0 +1,102 @@ +function load404Page() { + setHtmlLangAttribute(getBrowserLanguage()); + var translations = setTranslations(getBrowserLanguage()); + document.title = translations["404_Docs_Not_Found"]; + const page = document.getElementById("page"); + page.style.background = "url('/img/background_v0.1.x.webp') no-repeat center center fixed"; + page.style.backgroundSize = "cover"; + const container = document.createElement("div"); + container.classList.add("container-404"); + const cdIcon = document.createElement("i"); + cdIcon.classList.add("fa-solid", "fa-compact-disc"); + container.appendChild(cdIcon); + const rightContainer = document.createElement("div"); + rightContainer.classList.add("right-container-404"); + const h1 = document.createElement("h1"); + h1.textContent = translations["404_Docs_Not_Found"]; + rightContainer.appendChild(h1); + const p = document.createElement("p"); + p.textContent = translations["404_Docs_Not_Found_Contant"]; + rightContainer.appendChild(p); + const button = document.createElement("button"); + button.classList.add("go-home-button"); + const buttonIcon = document.createElement("i"); + buttonIcon.classList.add("fa-solid", "fa-arrow-left"); + button.appendChild(buttonIcon); + const buttonText = document.createElement("span"); + buttonText.classList.add("go-home-button-text"); + buttonText.textContent = translations["404_Go_Home"]; + button.appendChild(buttonText); + button.addEventListener("click", () => { + window.location.href = "/"; + }); + rightContainer.appendChild(button); + const langSelect = document.createElement("div"); + langSelect.classList.add("lang-select-404"); + const select = document.createElement("select"); + const availableLanguages = getAvailableLanguages(); + availableLanguages.forEach(lang => { + const option = document.createElement('option'); + option.value = lang.code; + option.textContent = lang.name; + select.appendChild(option); + }); + select.value = currentLang; + select.addEventListener("change", function () { + setHtmlLangAttribute(this.value); + translations = setTranslations(this.value); + document.title = translations["404_Docs_Not_Found"]; + h1.textContent = translations["404_Docs_Not_Found"]; + p.textContent = translations["404_Docs_Not_Found_Contant"]; + buttonText.textContent = translations["404_Go_Home"]; + }); + langSelect.appendChild(select); + rightContainer.appendChild(langSelect); + container.appendChild(rightContainer); + page.appendChild(container); +} + +// Load layout script +function loadLayoutScript404() { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = "/js/layout.js"; + script.async = true; + + script.onload = () => { + resolve(); + script.remove(); + }; + + script.onerror = () => { + const errorMsg = `Failed to load script: ${scriptUrl}`; + console.error(`[ScriptLoader] ${errorMsg}`); + reject(new Error(errorMsg)); + }; + + document.body.appendChild(script); + }); +} + +// Initialize app +async function initializeApp() { + try { + await Promise.all([ + loadLayoutScript404() + ]); + await Promise.all([ + loadScript("/js/i18n.js"), + loadCSSAsPromise("/css/layout.css"), + loadCSSAsPromise("/css/404.css"), + loadCSSAsPromise("/font-awesome/css/all.min.css") + ]) + createPage(); + load404Page() + } catch (error) { + console.error('App initialization error:', error); + } +} + +document.addEventListener('DOMContentLoaded', () => { + initializeApp(); +}); \ No newline at end of file diff --git a/docs/js/i18n.js b/docs/js/i18n.js new file mode 100644 index 0000000..c30c43f --- /dev/null +++ b/docs/js/i18n.js @@ -0,0 +1,91 @@ +/* + * i18n.js + * MeowBox-Docs + * Created by MoeCinnamo on 2025/11/26. + * + * This file contains the i18n strings for the web interface. + */ + +const en = { + "404_Docs_Not_Found": "404 Docs Not Found", + "404_Docs_Not_Found_Contant": "Sorry, the page you are looking for does not exist.", + "404_Go_Home": "Go Home" +}; + +const zhCN = { + "404_Docs_Not_Found": "文档未找到", + "404_Docs_Not_Found_Contant": "抱歉,您正在寻找的页面不存在。", + "404_Go_Home": "返回首页" +}; + +const zhTW = { + "404_Docs_Not_Found": "檔案未找到", + "404_Docs_Not_Found_Contant": "抱歉,您正在尋找的頁面不存在。", + "404_Go_Home": "回首頁" +}; + +const jp = { + "404_Docs_Not_Found": "ドキュメントが見つかりません", + "404_Docs_Not_Found_Contant": "申し訳ありません。要求されたページは存在しません。", + "404_Go_Home": "ホームページに戻る" +}; + +const languages_code = [ + { code: 'en', data: en }, + { code: 'zh-CN', data: zhCN }, + { code: 'zh-TW', data: zhTW }, + { code: 'ja', data: jp } +]; + +function getBrowserLanguage() { + try { + const browserLang = navigator.language || navigator.userLanguage; + + if (!browserLang) { + return 'en'; + } + + const langCode = browserLang.toLowerCase(); + + const exactMatch = languages_code.find(lang => + langCode === lang.code.toLowerCase() || + langCode.startsWith(lang.code.toLowerCase() + '-') + ); + + if (exactMatch) { + return exactMatch.code; + } + + if (langCode.startsWith('ja') || langCode.startsWith('jp')) { + return 'ja'; + } + + return 'en'; + } catch (error) { + console.error("Error detecting browser language:", error); + return 'en'; + } +} + +let currentLang = getBrowserLanguage(); + +function setTranslations(langCode) { + const langObj = languages_code.find(lang => lang.code === langCode); + return langObj ? langObj.data : en; +} + +function setHtmlLangAttribute(langCode) { + document.documentElement.setAttribute('lang', langCode); +} + +function getAvailableLanguages() { + return languages_code.map(lang => ({ + code: lang.code, + name: { + 'en': 'English', + 'zh-CN': '简体中文', + 'zh-TW': '繁體中文', + 'ja': '日本語' + }[lang.code] || lang.code + })); +} diff --git a/docs/js/index.js b/docs/js/index.js new file mode 100644 index 0000000..e69de29 diff --git a/docs/js/layout.js b/docs/js/layout.js new file mode 100644 index 0000000..09a000e --- /dev/null +++ b/docs/js/layout.js @@ -0,0 +1,97 @@ +// Load external script +function loadScript(scriptUrl) { + return new Promise((resolve, reject) => { + const script = document.createElement('script'); + script.src = scriptUrl; + script.async = true; + + script.onload = () => { + resolve(); + script.remove(); + }; + + script.onerror = () => { + const errorMsg = `Failed to load script: ${scriptUrl}`; + console.error(`[ScriptLoader] ${errorMsg}`); + reject(new Error(errorMsg)); + }; + + document.body.appendChild(script); + }); +} + +function loadCSS(url, callback, errorCallback, attributes = {}) { + const existingLinks = document.querySelectorAll('link[rel="stylesheet"]'); + for (let i = 0; i < existingLinks.length; i++) { + if (existingLinks[i].href === url || existingLinks[i].href.endsWith(url)) { + if (typeof callback === 'function') { + callback(); + } + return existingLinks[i]; + } + } + + const link = document.createElement('link'); + + link.rel = attributes.rel || 'stylesheet'; + link.type = attributes.type || 'text/css'; + link.href = url; + + if (attributes.media) link.media = attributes.media; + if (attributes.id) link.id = attributes.id; + if (attributes.crossOrigin) link.crossOrigin = attributes.crossOrigin; + + link.onload = function () { + if (typeof callback === 'function') { + callback(); + } + }; + + link.onerror = function (err) { + if (typeof errorCallback === 'function') { + errorCallback(err); + } else { + console.error(`Failed to load CSS: ${url}`, err); + } + }; + + const head = document.head || document.getElementsByTagName('head')[0]; + head.appendChild(link); + + return link; +} + +function loadCSSAsPromise(url, attributes = {}) { + return new Promise((resolve, reject) => { + loadCSS( + url, + resolve, + reject, + attributes + ); + }); +} + +function loadMD5Script() { + return new Promise((resolve, reject) => { + if (typeof md5 !== 'undefined') { + resolve(); // MD5 library already loaded + return; + } + const script = document.createElement('script'); + script.src = '/js/md5.min.js'; + script.async = true; + script.onload = () => resolve(); + script.onerror = () => { + console.error('Failed to load MD5 library'); + reject(new Error('MD5 library load failed')); + }; + document.head.appendChild(script); + }); +} + +function createPage() { + const main = document.createElement('div'); + main.id = "page"; + document.body.appendChild(main); +} \ No newline at end of file diff --git a/docs/js/md5.min.js b/docs/js/md5.min.js new file mode 100644 index 0000000..3777aed --- /dev/null +++ b/docs/js/md5.min.js @@ -0,0 +1 @@ +!function (n) { "use strict"; function d(n, t) { var r = (65535 & n) + (65535 & t); return (n >> 16) + (t >> 16) + (r >> 16) << 16 | 65535 & r } function f(n, t, r, e, o, u) { return d((u = d(d(t, n), d(e, u))) << o | u >>> 32 - o, r) } function l(n, t, r, e, o, u, c) { return f(t & r | ~t & e, n, t, o, u, c) } function g(n, t, r, e, o, u, c) { return f(t & e | r & ~e, n, t, o, u, c) } function v(n, t, r, e, o, u, c) { return f(t ^ r ^ e, n, t, o, u, c) } function m(n, t, r, e, o, u, c) { return f(r ^ (t | ~e), n, t, o, u, c) } function c(n, t) { var r, e, o, u; n[t >> 5] |= 128 << t % 32, n[14 + (t + 64 >>> 9 << 4)] = t; for (var c = 1732584193, f = -271733879, i = -1732584194, a = 271733878, h = 0; h < n.length; h += 16)c = l(r = c, e = f, o = i, u = a, n[h], 7, -680876936), a = l(a, c, f, i, n[h + 1], 12, -389564586), i = l(i, a, c, f, n[h + 2], 17, 606105819), f = l(f, i, a, c, n[h + 3], 22, -1044525330), c = l(c, f, i, a, n[h + 4], 7, -176418897), a = l(a, c, f, i, n[h + 5], 12, 1200080426), i = l(i, a, c, f, n[h + 6], 17, -1473231341), f = l(f, i, a, c, n[h + 7], 22, -45705983), c = l(c, f, i, a, n[h + 8], 7, 1770035416), a = l(a, c, f, i, n[h + 9], 12, -1958414417), i = l(i, a, c, f, n[h + 10], 17, -42063), f = l(f, i, a, c, n[h + 11], 22, -1990404162), c = l(c, f, i, a, n[h + 12], 7, 1804603682), a = l(a, c, f, i, n[h + 13], 12, -40341101), i = l(i, a, c, f, n[h + 14], 17, -1502002290), c = g(c, f = l(f, i, a, c, n[h + 15], 22, 1236535329), i, a, n[h + 1], 5, -165796510), a = g(a, c, f, i, n[h + 6], 9, -1069501632), i = g(i, a, c, f, n[h + 11], 14, 643717713), f = g(f, i, a, c, n[h], 20, -373897302), c = g(c, f, i, a, n[h + 5], 5, -701558691), a = g(a, c, f, i, n[h + 10], 9, 38016083), i = g(i, a, c, f, n[h + 15], 14, -660478335), f = g(f, i, a, c, n[h + 4], 20, -405537848), c = g(c, f, i, a, n[h + 9], 5, 568446438), a = g(a, c, f, i, n[h + 14], 9, -1019803690), i = g(i, a, c, f, n[h + 3], 14, -187363961), f = g(f, i, a, c, n[h + 8], 20, 1163531501), c = g(c, f, i, a, n[h + 13], 5, -1444681467), a = g(a, c, f, i, n[h + 2], 9, -51403784), i = g(i, a, c, f, n[h + 7], 14, 1735328473), c = v(c, f = g(f, i, a, c, n[h + 12], 20, -1926607734), i, a, n[h + 5], 4, -378558), a = v(a, c, f, i, n[h + 8], 11, -2022574463), i = v(i, a, c, f, n[h + 11], 16, 1839030562), f = v(f, i, a, c, n[h + 14], 23, -35309556), c = v(c, f, i, a, n[h + 1], 4, -1530992060), a = v(a, c, f, i, n[h + 4], 11, 1272893353), i = v(i, a, c, f, n[h + 7], 16, -155497632), f = v(f, i, a, c, n[h + 10], 23, -1094730640), c = v(c, f, i, a, n[h + 13], 4, 681279174), a = v(a, c, f, i, n[h], 11, -358537222), i = v(i, a, c, f, n[h + 3], 16, -722521979), f = v(f, i, a, c, n[h + 6], 23, 76029189), c = v(c, f, i, a, n[h + 9], 4, -640364487), a = v(a, c, f, i, n[h + 12], 11, -421815835), i = v(i, a, c, f, n[h + 15], 16, 530742520), c = m(c, f = v(f, i, a, c, n[h + 2], 23, -995338651), i, a, n[h], 6, -198630844), a = m(a, c, f, i, n[h + 7], 10, 1126891415), i = m(i, a, c, f, n[h + 14], 15, -1416354905), f = m(f, i, a, c, n[h + 5], 21, -57434055), c = m(c, f, i, a, n[h + 12], 6, 1700485571), a = m(a, c, f, i, n[h + 3], 10, -1894986606), i = m(i, a, c, f, n[h + 10], 15, -1051523), f = m(f, i, a, c, n[h + 1], 21, -2054922799), c = m(c, f, i, a, n[h + 8], 6, 1873313359), a = m(a, c, f, i, n[h + 15], 10, -30611744), i = m(i, a, c, f, n[h + 6], 15, -1560198380), f = m(f, i, a, c, n[h + 13], 21, 1309151649), c = m(c, f, i, a, n[h + 4], 6, -145523070), a = m(a, c, f, i, n[h + 11], 10, -1120210379), i = m(i, a, c, f, n[h + 2], 15, 718787259), f = m(f, i, a, c, n[h + 9], 21, -343485551), c = d(c, r), f = d(f, e), i = d(i, o), a = d(a, u); return [c, f, i, a] } function i(n) { for (var t = "", r = 32 * n.length, e = 0; e < r; e += 8)t += String.fromCharCode(n[e >> 5] >>> e % 32 & 255); return t } function a(n) { var t = []; for (t[(n.length >> 2) - 1] = void 0, e = 0; e < t.length; e += 1)t[e] = 0; for (var r = 8 * n.length, e = 0; e < r; e += 8)t[e >> 5] |= (255 & n.charCodeAt(e / 8)) << e % 32; return t } function e(n) { for (var t, r = "0123456789abcdef", e = "", o = 0; o < n.length; o += 1)t = n.charCodeAt(o), e += r.charAt(t >>> 4 & 15) + r.charAt(15 & t); return e } function r(n) { return unescape(encodeURIComponent(n)) } function o(n) { return i(c(a(n = r(n)), 8 * n.length)) } function u(n, t) { return function (n, t) { var r, e = a(n), o = [], u = []; for (o[15] = u[15] = void 0, 16 < e.length && (e = c(e, 8 * n.length)), r = 0; r < 16; r += 1)o[r] = 909522486 ^ e[r], u[r] = 1549556828 ^ e[r]; return t = c(o.concat(a(t)), 512 + 8 * t.length), i(c(u.concat(t), 640)) }(r(n), r(t)) } function t(n, t, r) { return t ? r ? u(t, n) : e(u(t, n)) : r ? o(n) : e(o(n)) } "function" == typeof define && define.amd ? define(function () { return t }) : "object" == typeof module && module.exports ? module.exports = t : n.md5 = t }(this); \ No newline at end of file diff --git a/main.go b/main.go index fd13438..1e2bc98 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,10 @@ +/* + * The simplest web service + * Created by MoeCinnamo on 2025/11/26. + * + * This is a simple web service that serves static files from the "docs" directory. + */ + package main import ( @@ -138,6 +145,7 @@ func route() { http.HandleFunc("/font-awesome/", staticFileHandler) http.HandleFunc("/js/", staticFileHandler) http.HandleFunc("/img/", staticFileHandler) + http.HandleFunc("/markdown/", staticFileHandler) } func getContentType(filename string) string {