From 76272b26a18775a8cec3fa27e0b0ea92fa974e6d Mon Sep 17 00:00:00 2001 From: quartinal Date: Sat, 25 Jan 2025 17:28:22 -0800 Subject: [PATCH] just gonna push this before massively redesigning the popup modal under preston's recruitment --- .gitignore | 2 + README.md | 2 +- css/styles.css | 439 ++++++++++++--------- dist-templates/messages/sitePerformance.js | 49 +++ dist-templates/packages/pretty-ms/index.js | 1 + dist-templates/template-engine/index.js | 323 +++++++++++++++ getTsupTargets.js | 28 ++ index.html | 9 +- js/darkmode.js | 9 +- js/main.js | 13 +- js/tabs.js | 48 +++ package.json | 10 +- tsup.config.js | 3 +- tsup.config.misc.js | 28 ++ 14 files changed, 758 insertions(+), 206 deletions(-) create mode 100644 dist-templates/messages/sitePerformance.js create mode 100644 dist-templates/packages/pretty-ms/index.js create mode 100644 dist-templates/template-engine/index.js create mode 100644 getTsupTargets.js create mode 100644 js/tabs.js create mode 100644 tsup.config.misc.js diff --git a/.gitignore b/.gitignore index 7f16228..7c18ea9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ dist/ +dist-misc/ node_modules/ pnpm-lock.yaml .vercel # Local Netlify folder .netlify +.idea/ \ No newline at end of file diff --git a/README.md b/README.md index df1e8f7..96e8f49 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ You are welcome to open a pull request to contribute! > You are more likely to be helped in the Discord Server than open an issue. You **MUST** join the discord server to apply for staff. > [!NOTE] -> If you are forking this repository and want to keep your fork up to date. You can use the sync fork button **(safer)** on the repository or https://github.com/apps/pull (Github Only) to auto sync **(but read the warning below)**. +> If you are forking this repository and want to keep your fork up to date, you can use the sync fork button **(safer)** on the repository or https://github.com/apps/pull (Github Only) to auto sync **(but read the warning below)**. > [!WARNING] > If you choose to use the pull GitHub app, it deletes all the changes you made when it syncs to a new commit; so you should backup your changes. diff --git a/css/styles.css b/css/styles.css index 8951063..91368d4 100644 --- a/css/styles.css +++ b/css/styles.css @@ -1,17 +1,16 @@ /* General Styles */ body { - font-family: 'Arial', sans-serif; + font-family: 'Raleway', sans-serif; background-color: var(--ctp-macchiato-overlay0); - background-size: auto; margin: 0; padding: 0; - text-align: center; - display: flex; - flex-direction: column; min-height: 100vh; overflow-x: hidden; color: var(--ctp-macchiato-mantle); - transition: background-color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); + display: grid; + grid-template-rows: auto 1fr auto; + transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1); + text-align: center; } body.dark-mode { @@ -22,88 +21,193 @@ body.dark-mode { header { background-color: var(--ctp-macchiato-green); color: var(--ctp-macchiato-crust); - padding: 20px 0; - text-align: center; - transition: background-color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); + padding: 1.5rem 0; + transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1); } header h1 { margin: 0; + transform: translateY(0); + transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); +} + +header h1:hover { + transform: translateY(-2px); } main { - flex: 1; - padding: 20px; + display: grid; + gap: 2rem; + padding: 2rem; + max-width: 1200px; + margin: 0 auto; + width: 100%; + place-items: center; } .darkmodediv { - padding-left: 480px; - padding-right: 480px; + padding: 1rem; background: var(--ctp-macchiato-rosewater); -} - -.counter, .info, .clients, .danger-zone { - margin-bottom: 20px; + border-radius: 8px; + margin: 0 auto; + max-width: 800px; + width: 100%; } .Container18, .Container15, .ContainerOther { display: flex; flex-wrap: wrap; justify-content: center; - gap: 40px; - margin: 20px 0; + align-items: center; + gap: 1rem; + width: 100%; + max-width: 1200px; + padding: 2rem; + background-color: var(--ctp-macchiato-surface0); + border-radius: 12px; + margin: 1rem 0; } +/* To prevent buttons from becoming too small on narrow screens */ +.Container18 button, +.Container15 button, +.ContainerOther button, +.Container18 .source-btn, +.Container15 .source-btn, +.ContainerOther .source-btn, +.Container18 .dsc-btn, +.Container15 .dsc-btn, +.ContainerOther .dsc-btn, +.Container18 .clr-btn, +.Container15 .clr-btn, +.ContainerOther .clr-btn { + min-width: 120px; + margin: 0.5rem; + flex-shrink: 0; +} + +/* Add a container for each version category for better organization */ +.version-category { + width: 100%; + margin: 1rem 0; + padding: 1rem; + background-color: var(--ctp-macchiato-surface0); + border-radius: 8px; +} + +/* Make sure the category title is visible */ +.version-category h2 { + margin-bottom: 1rem; + color: var(--ctp-macchiato-text); +} + +/* Responsive adjustments */ +@media (max-width: 768px) { + .Container18, .Container15, .ContainerOther { + padding: 0.5rem; + } + + .Container18 button, + .Container15 button, + .ContainerOther button, + .Container18 .source-btn, + .Container15 .source-btn, + .ContainerOther .source-btn, + .Container18 .dsc-btn, + .Container15 .dsc-btn, + .ContainerOther .dsc-btn, + .Container18 .clr-btn, + .Container15 .clr-btn, + .ContainerOther .clr-btn { + min-width: 100px; + font-size: 0.9rem; + padding: 0.5rem 1rem; + } +} + +@media (max-width: 480px) { + .Container18, .Container15, .ContainerOther { + justify-content: flex-start; + overflow-x: auto; + padding: 1rem 0.5rem; + -webkit-overflow-scrolling: touch; + scrollbar-width: thin; + } + + .Container18::-webkit-scrollbar, + .Container15::-webkit-scrollbar, + .ContainerOther::-webkit-scrollbar { + height: 4px; + } + + .Container18::-webkit-scrollbar-thumb, + .Container15::-webkit-scrollbar-thumb, + .ContainerOther::-webkit-scrollbar-thumb { + background-color: var(--ctp-macchiato-overlay2); + border-radius: 4px; + } +} + +/* Base button styles */ button, .source-btn, .dsc-btn, .clr-btn { background-color: var(--ctp-macchiato-green); color: var(--ctp-macchiato-mantle); - padding: 10px 20px; - font-size: 16px; + padding: 0.75rem 1.5rem; + font-size: 1rem; cursor: pointer; border: none; - border-radius: 5px; + border-radius: 8px; text-decoration: none; - display: inline-block; - transition: background-color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); } -.clientbutton button { - background-color: var(--ctp-macchiato-green); +/* GSAP-like animations only for regular buttons */ +button { + position: relative; + overflow: hidden; + transform-origin: center; + transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), + background-color 0.3s cubic-bezier(0.16, 1, 0.3, 1), + box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1); +} + +button::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient( + 120deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + transform: translateX(-100%); + transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); +} + +button:hover::before { + transform: translateX(100%); } button:hover { - transform: scale(+1.14) translateX(-20px); + transform: scale(1.05) translateY(-2px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } -button:focus { - outline: 3px solid var(--ctp-macchiato-overlay2); - outline-offset: 2px; +button:active { + transform: scale(0.95); + transition-duration: 0.1s; } -.clr-btn:hover { - background-color: var(--ctp-macchiato-peach); - transform: scale(+1.14) translateX(-20px); -} - -.dsc-btn:hover { - background-color: var(--ctp-macchiato-mauve); - transform: scale(+1.14) translateX(-20px); - color: var(--ctp-macchiato-mantle); -} - -.source-btn:hover { - background-color: var(--ctp-macchiato-mantle); - transform: scale(+1.14) translateX(-20px); -} - -.source-btn { - background-color: var(--ctp-macchiato-mantle); /* Black color for GitHub button */ +/* Simple transitions for dsc-btn and clr-btn */ +.dsc-btn, .clr-btn { + transition: background-color 0.3s ease; } .dsc-btn { - background-color: var(--ctp-macchiato-crust); - color: var(--ctp-macchiato-lavender); - transition: 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55); + background-color: var(--ctp-macchiato-mauve); } .clr-btn { @@ -111,183 +215,148 @@ button:focus { } .search-container { - margin: 20px 0; + display: grid; + place-items: center; + gap: 1rem; + margin: 2rem 0; + width: 100%; } #search-bar { background-color: var(--ctp-macchiato-mantle); - padding: 10px; - border-radius: 35px; - width: 50%; + padding: 1rem 1.5rem; + border-radius: 999px; + width: 100%; + max-width: 500px; outline: none; - border: 4px solid var(--ctp-macchiato-green); + border: 3px solid var(--ctp-macchiato-green); color: var(--ctp-macchiato-text); + transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1); } #search-bar:focus { - border-width: 5px; -} - -#search-bar::placeholder { - color: var(--ctp-macchiato-text); + border-width: 4px; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } .footer { - display: flex; - justify-content: center; - align-items: center; - gap: 40px; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 2rem; + padding: 1.5rem; background-color: var(--ctp-macchiato-overlay1); - color: var(--ctp-macchiato-mantle); /* Light text color for footer */ - padding: 10px; - text-align: center; - opacity: 0.9; - transition: background-color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); + color: var(--ctp-macchiato-text); + place-items: center; + transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1); } -.footer a { - color: var(--ctp-macchiato-text); /* Light text color for footer links */ - text-decoration: none; - margin: 0 10px; - opacity: 1; -} - -.footer a:hover { - text-decoration: underline; - opacity: 1; -} - -.footer button { - color: var(--ctp-macchiato-mantle); - padding: 10px 20px; - font-size: 16px; - cursor: pointer; - border: none; - border-radius: 5px; - text-decoration: none; - display: inline-block; - transition: background-color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), transform 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); - opacity: 1; -} - -/* Modal Styles */ .modal { display: none; position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - background-color: var(--ctp-macchiato-mantle); - justify-content: center; - align-items: center; + inset: 0; + background-color: rgba(0, 0, 0, 0.5); + place-items: center; + backdrop-filter: blur(4px); } .modal-content { background-color: var(--ctp-macchiato-text); - padding: 20px; - border-radius: 10px; - width: 80%; - max-width: 400px; - text-align: center; - box-shadow: 0px 4px 8px var(--ctp-macchiato-mantle); - transition: background-color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55), color 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55); + padding: 2rem; + border-radius: 12px; + width: 90%; + max-width: 500px; + display: grid; + gap: 1.5rem; + place-items: center; + transform: translateY(0); + transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); } -.modal h2 { - color: var(--ctp-macchiato-surface1); +/* Source button with minimal animation */ +.source-btn { + background-color: var(--ctp-macchiato-mantle); + transition: background-color 0.3s ease; } -.modal p { - color: var(--ctp-macchiato-mantle); - margin-bottom: 20px; -} - -.modal button { - background-color: var(--ctp-macchiato-green); - color: var(--ctp-macchiato-text); - padding: 10px 20px; - font-size: 16px; - cursor: pointer; - border: none; - border-radius: 5px; - margin: 5px; -} - -.modal button.cancel-btn { - background-color: var(--ctp-macchiato-peach); -} - -.modal button:hover { - background-color: var(--ctp-macchiato-green); -} - -.modal button.cancel-btn:hover { - background-color: var(--ctp-macchiato-maroon); -} - -.copy-link { - background-color: var(--ctp-macchiato-lavender); - padding: 10px; - border: 1px solid var(--ctp-macchiato-text); - border-radius: 5px; - margin-bottom: 15px; -} - -.copy-btn { - background-color: var(--ctp-macchiato-mauve); -} - -.copy-btn:hover { - filter: brightness(1.2); -} - -/* Dark Mode Styles */ +/* Dark Mode enhancements */ body.dark-mode .modal-content { background-color: var(--ctp-macchiato-mantle); - color: var(--ctp-macchiato-text); -} - -body.dark-mode .modal h2 { - color: var(--ctp-macchiato-text); -} - -body.dark-mode .modal p { - color: var(--ctp-macchiato-text); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2); } body.dark-mode #search-bar { background-color: var(--ctp-macchiato-overlay0); - color: var(--ctp-macchiato-text); - border-color: var(--ctp-macchiato-overlay1); -} - -body.dark-mode #search-bar:focus { - border-color: var(--ctp-macchiato-green); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } body.dark-mode .footer { - background-color: var(--ctp-macchiato-overlay0); /* Dark gray color for footer in dark mode */ - color: var(--ctp-macchiato-text); /* Light text color for footer in dark mode */ + background-color: var(--ctp-macchiato-overlay0); + border-top: 1px solid var(--ctp-macchiato-overlay1); } -body.dark-mode .footer a { - color: var(--ctp-macchiato-text); /* Light text color for footer links in dark mode */ +/* Responsive centering for smaller screens */ +@media (max-width: 768px) { + .Container18, .Container15, .ContainerOther { + grid-template-columns: 1fr; + max-width: 400px; + margin: 0 auto; + } + + .darkmodediv { + padding: 1rem; + margin: 0 1rem; + } } -body.dark-mode .footer button.server-list { - background-color: var(--ctp-macchiato-crust); /* Black color for Server List button in dark mode */ +/* Tabs styling */ +.tabs { + display: flex; + justify-content: center; + gap: 0.5rem; + margin-bottom: 2rem; + padding: 0 1rem; } -body.dark-mode .footer button.server-list:hover { - background-color: var(--ctp-macchiato-overlay1); /* Slightly lighter shade for hover effect in dark mode */ +.tab { + background-color: var(--ctp-macchiato-surface0); + color: var(--ctp-macchiato-text); + padding: 0.75rem 1.5rem; + border: none; + border-radius: 8px; + cursor: pointer; + font-family: 'Raleway', sans-serif; + font-weight: 500; + transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1); } -body.dark-mode .footer button.eaglerrinth-mod-list { - background-color: var(--ctp-macchiato-mauve); /* Same color as Discord link button in dark mode */ +.tab.active { + background-color: var(--ctp-macchiato-mauve); + color: var(--ctp-macchiato-base); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } -body.dark-mode .footer button.eaglerrinth-mod-list:hover { - filter: brightness(1.2); /* Slightly lighter shade for hover effect in dark mode */ +.tab:hover:not(.active) { + background-color: var(--ctp-macchiato-surface1); + transform: translateY(-1px); } + +.tab-content { + display: none; + opacity: 0; + transform: translateY(10px); + transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1); +} + +.tab-content.active { + display: block; + opacity: 1; + transform: translateY(0); +} + +/* Version text styling */ +.version-text { + display: none; /* Hide the original version text */ +} \ No newline at end of file diff --git a/dist-templates/messages/sitePerformance.js b/dist-templates/messages/sitePerformance.js new file mode 100644 index 0000000..fd19270 --- /dev/null +++ b/dist-templates/messages/sitePerformance.js @@ -0,0 +1,49 @@ +import prettifyMilliseconds from '../packages/pretty-ms/index.js'; + +export default function getPageLoadTime() { + const [navigation] = performance.getEntriesByType('navigation'); + const loadTime = navigation.loadEventEnd - navigation.startTime; + const prettifiedLoadTime = prettifyMilliseconds(loadTime); + + return { loadTime, prettifiedLoadTime }; +} + +export function initializePeformanceChecks() { + window.addEventListener('load', () => { + const { loadTime, prettifiedLoadTime } = getPageLoadTime(); + const { sanitize } = self.DOMPurify; + + if (loadTime >= 2500) { + document.body.setAttribute('data-slow', 'true'); + } + + const pageLoadedSlowly = Boolean(document.body.dataset.slow); + + if (pageLoadedSlowly) + document.body.classList.add('performance-popover'); + + if (document.body.classList.contains('performance-popover')) { + document.body.innerHTML = sanitize( + ` +
+

Whoops!

+

Looks like ${location.host} loaded slower than usual!

+

Precisely, it loaded in ${prettifiedLoadTime}.

+ +

+ Do you want to turn off script obfuscation or continue? +

+
+ ` + ); + + const styleSheet = document.createElement('style'); + document.head.appendChild(styleSheet); + + const { sheet } = styleSheet; + const rulesLength = sheet.cssRules.length; + + + } + }); +} \ No newline at end of file diff --git a/dist-templates/packages/pretty-ms/index.js b/dist-templates/packages/pretty-ms/index.js new file mode 100644 index 0000000..02525c0 --- /dev/null +++ b/dist-templates/packages/pretty-ms/index.js @@ -0,0 +1 @@ +export { default as default } from 'pretty-ms'; \ No newline at end of file diff --git a/dist-templates/template-engine/index.js b/dist-templates/template-engine/index.js new file mode 100644 index 0000000..f821686 --- /dev/null +++ b/dist-templates/template-engine/index.js @@ -0,0 +1,323 @@ +export const TemplateEngine = { + state: new Proxy({}, { + set(target, property, value) { + target[property] = value; + TemplateEngine.updateDependents(property); + return true; + } + }), + + dependencyMap: new Map(), + + components: new Map(), + + init() { + this.registerComponents(); + this.processDOM(document.body); + this.setupEventListeners(); + }, + + registerComponent(name, template) { + this.components.set(name, template); + }, + + registerComponents() { + const templates = document.querySelectorAll('template[data-component]'); + templates.forEach(template => { + const name = template.dataset.component; + this.components.set(name, template.innerHTML); + template.remove(); + }); + }, + + setupTwoWayBinding(element) { + if (element.hasAttribute('bind')) { + const bindExpression = element.getAttribute('bind'); + const [stateKey] = bindExpression.split('.'); + + element.value = this.evaluateExpression(bindExpression); + + this.addDependency(stateKey, element); + + element.addEventListener('input', (e) => { + const value = element.type === 'checkbox' ? element.checked : element.value; + this.setState(bindExpression, value); + }); + } + }, + + setupEventListeners() { + document.addEventListener('click', (e) => { + let target = e.target; + while (target && target !== document) { + const eventAttrs = [...target.attributes].filter(attr => + attr.name.startsWith('@') + ); + + eventAttrs.forEach(attr => { + const handler = attr.value; + try { + const func = new Function('event', ` + const target = event.target; + ${handler} + `); + func(e); + } catch (error) { + console.error(`Error in event handler "${handler}":`, error); + } + }); + + target = target.parentNode; + } + }); + }, + + processDOM(rootElement) { + this.processComponents(rootElement); + this.evaluateAttributes(rootElement); + this.processControlFlow(rootElement); + this.processLoops(rootElement); + this.setupReactivity(rootElement); + }, + + processComponents(element) { + this.components.forEach((template, name) => { + const components = element.getElementsByTagName(name); + [...components].forEach(component => { + const props = [...component.attributes].reduce((acc, attr) => { + acc[attr.name] = this.evaluateExpression(attr.value); + return acc; + }, {}); + + const content = template.replace(/\${([^}]+)}/g, (_, expr) => { + return this.evaluateExpression(expr, props); + }); + + component.innerHTML = content; + }); + }); + }, + + processLoops(element) { + const processForLoop = (node) => { + const forExpr = node.textContent.trim().slice(4); + const matches = forExpr.match(/(\w+)\s+of\s+(.+)/); + + if (!matches) return; + + const [_, itemName, arrayExpr] = matches; + const array = this.evaluateExpression(arrayExpr); + + if (!Array.isArray(array)) { + throw new Error(`Expression "${arrayExpr}" must evaluate to an array`); + } + + const template = document.createDocumentFragment(); + let currentNode = node.nextSibling; + + while (currentNode && currentNode.textContent.trim() !== 'endfor') { + template.appendChild(currentNode.cloneNode(true)); + currentNode = currentNode.nextSibling; + } + + const parent = node.parentNode; + array.forEach((item, index) => { + const context = { + [itemName]: item, + index + }; + + const instance = template.cloneNode(true); + this.evaluateWithContext(instance, context); + parent.insertBefore(instance, node); + }); + + while (currentNode && currentNode.textContent.trim() !== 'endfor') { + const next = currentNode.nextSibling; + parent.removeChild(currentNode); + currentNode = next; + } + parent.removeChild(node); + if (currentNode) parent.removeChild(currentNode); + }; + + const walker = document.createTreeWalker( + element, + NodeFilter.SHOW_COMMENT, + null, + false + ); + + const forNodes = []; + let currentNode; + while (currentNode = walker.nextNode()) { + if (currentNode.textContent.trim().startsWith('for ')) { + forNodes.push(currentNode); + } + } + + forNodes.forEach(node => processForLoop(node)); + }, + + setupReactivity(element) { + [...element.attributes || []].forEach(attr => { + const match = attr.value.match(/^{(.+)}$/); + if (match) { + const expression = match[1]; + const stateKeys = this.extractStateKeys(expression); + + stateKeys.forEach(key => { + this.addDependency(key, element); + }); + } + }); + + [...element.children].forEach(child => this.setupReactivity(child)); + }, + + extractStateKeys(expression) { + const stateKeys = new Set(); + const matches = expression.match(/\b\w+\b/g) || []; + matches.forEach(match => { + if (this.state.hasOwnProperty(match)) { + stateKeys.add(match); + } + }); + return Array.from(stateKeys); + }, + + addDependency(stateKey, element) { + if (!this.dependencyMap.has(stateKey)) { + this.dependencyMap.set(stateKey, new Set()); + } + this.dependencyMap.get(stateKey).add(element); + }, + + updateDependents(stateKey) { + const dependents = this.dependencyMap.get(stateKey); + if (dependents) { + dependents.forEach(element => { + this.evaluateAttributes(element); + }); + } + }, + + setState(path, value) { + const parts = path.split('.'); + let current = this.state; + + for (let i = 0; i < parts.length - 1; i++) { + current = current[parts[i]]; + } + + current[parts[parts.length - 1]] = value; + }, + + evaluateExpression(expression, context = {}) { + try { + const func = new Function( + ...Object.keys(context), + `return ${expression}` + ); + return func(...Object.values(context)); + } catch (error) { + throw new Error(`Error evaluating expression "${expression}": ${error.message}`); + } + }, + + evaluateWithContext(element, context) { + [...element.attributes || []].forEach(attr => { + const match = attr.value.match(/^{(.+)}$/); + if (match) { + const expression = match[1]; + try { + const result = this.evaluateExpression(expression, context); + element.setAttribute(attr.name, result); + } catch (error) { + console.error(error); + } + } + }); + + [...element.children].forEach(child => this.evaluateWithContext(child, context)); + }, + + evaluateAttributes(element) { + const attributes = [...element.attributes || []]; + + attributes.forEach(attr => { + const match = attr.value.match(/^{(.+)}$/); + if (match) { + const expression = match[1]; + try { + const result = this.evaluateExpression(expression); + if (result === undefined || result === null) { + throw new Error(`Variable "${expression}" is undefined or null`); + } + element.setAttribute(attr.name, result); + } catch (error) { + throw new Error(`Error evaluating expression "${expression}" in attribute "${attr.name}": ${error.message}`); + } + } + }); + + [...element.children].forEach(child => this.evaluateAttributes(child)); + }, + + processControlFlow(element) { + const processIfStatements = (startNode) => { + let currentNode = startNode; + let removeNodes = []; + let keepContent = false; + let foundTruthy = false; + + while (currentNode) { + if (currentNode.nodeType === Node.COMMENT_NODE) { + const content = currentNode.textContent.trim(); + + if (content.startsWith('if ')) { + const condition = content.slice(3); + try { + keepContent = this.evaluateExpression(condition); + foundTruthy = keepContent; + } catch (error) { + throw new Error(`Error evaluating if condition "${condition}": ${error.message}`); + } + } else if (content === 'else if' || content === 'else') { + keepContent = !foundTruthy; + if (keepContent && content === 'else if') { + foundTruthy = true; + } + } else if (content === 'endif') { + break; + } + + removeNodes.push(currentNode); + } else if (!keepContent && currentNode.nodeType === Node.ELEMENT_NODE) { + removeNodes.push(currentNode); + } + + currentNode = currentNode.nextSibling; + } + + removeNodes.forEach(node => node.parentNode.removeChild(node)); + }; + + const walker = document.createTreeWalker( + element, + NodeFilter.SHOW_COMMENT, + null, + false + ); + + const ifNodes = []; + let currentNode; + while (currentNode = walker.nextNode()) { + if (currentNode.textContent.trim().startsWith('if ')) { + ifNodes.push(currentNode); + } + } + + ifNodes.forEach(node => processIfStatements(node)); + } +}; \ No newline at end of file diff --git a/getTsupTargets.js b/getTsupTargets.js new file mode 100644 index 0000000..b8878a6 --- /dev/null +++ b/getTsupTargets.js @@ -0,0 +1,28 @@ +import bcd from '@mdn/browser-compat-data/forLegacyNode'; + +function getTsupTargets() { + const popularBrowsers = ['chrome', 'firefox', 'safari', 'edge']; + + return Object.entries(bcd.browsers) + .filter(([name]) => popularBrowsers.includes(name.toLowerCase())) + .map(([name, data]) => { + const browserName = name.toLowerCase(); + + const latestVersion = Object.keys(data.releases || {}) + .filter(versionKey => { + const release = data.releases?.[versionKey]; + return release?.status === 'current'; + }) + .map(versionKey => parseFloat(versionKey)) + .sort((a, b) => b - a)[0]; + + if (!latestVersion) { + return null; + } + + return `${browserName}${Math.floor(latestVersion)}`; + }) + .filter(Boolean); +} + +export const target = getTsupTargets(); diff --git a/index.html b/index.html index 7795e41..fae63d0 100644 --- a/index.html +++ b/index.html @@ -9,6 +9,7 @@ + - + + - + + @@ -71,8 +74,6 @@

Pick a Client:

- -
diff --git a/js/darkmode.js b/js/darkmode.js index c58823b..c7c1739 100644 --- a/js/darkmode.js +++ b/js/darkmode.js @@ -1,13 +1,11 @@ import { hexToRGB, - pushStyles, + pushStyles, selectClass, - selectId, + selectId, selectTag, } from "./helperFunctions.js"; -global.querySelectorAll = document.querySelectorAll; - $(function() { function applyStyles(elements, styles) { elements.forEach(element => pushStyles(element, styles)); @@ -20,13 +18,12 @@ $(function() { color: hexToRGB('#f1f1f1') } : { backgroundColor: '#f1f1f1', - color: 'black', + color: 'var(--ctp-macchiato-mantle)', backgroundImage: "url('/images/grass-background.jpg')" }; pushStyles(body, commonStyles); - applyStyles(document.querySelectorAll('p'), { color: commonStyles.color }); applyStyles([selectTag('h2'), selectTag('h1')], { color: commonStyles.color }); if (isChecked) { diff --git a/js/main.js b/js/main.js index ab2841e..670cee4 100644 --- a/js/main.js +++ b/js/main.js @@ -61,9 +61,13 @@ $(function() { } } - function updateShowModded() { - toggleVisibility("#moddedButtons", $("#showModded").is(":checked")); - } + // fix something very absurd + window.addEventListener('load', () => { + if (!($('#darkModeCheckbox').is(':checked'))) { + $('.footer p').removeAttr('style'); + $('.footer p').css('color', 'var(--ctp-macchiato-text)'); + } + }); $("#darkModeCheckbox").on("change", updateDarkMode); updateDarkMode(); @@ -71,7 +75,4 @@ $(function() { selectId('clr-data-modal').addEventListener('click', handleClrModalClick); $('#search-bar').on('keyup', handleSearchBarKeyup); - - $("#showModded").on("change", updateShowModded); - updateShowModded(); }); \ No newline at end of file diff --git a/js/tabs.js b/js/tabs.js new file mode 100644 index 0000000..22e689e --- /dev/null +++ b/js/tabs.js @@ -0,0 +1,48 @@ +document.addEventListener('DOMContentLoaded', function() { + const tabsContainer = document.createElement('div'); + tabsContainer.className = 'tabs'; + + const tabs = [ + { id: 'tab18', text: '1.8 Clients', content: '#desktopVersion18' }, + { id: 'tabModded', text: 'Modded Clients', content: '#moddedButtons' }, + { id: 'tab152', text: '1.5.2 Clients', content: '#desktopVersion152' }, + { id: 'tabOther', text: 'Other Versions', content: '#desktopVersionOther' } + ]; + + const searchContainer = document.querySelector('.search-container'); + + tabs.forEach((tab, index) => { + const button = document.createElement('button'); + button.className = `tab ${index === 0 ? 'active' : ''}`; + button.setAttribute('data-tab', tab.content); + button.textContent = tab.text; + tabsContainer.appendChild(button); + }); + + searchContainer.after(tabsContainer); + + document.querySelectorAll('.version-text').forEach(text => { + text.style.display = 'none'; + }); + + document.querySelector(tabs[0].content).classList.add('tab-content', 'active'); + tabs.slice(1).forEach(tab => { + document.querySelector(tab.content).classList.add('tab-content'); + }); + + tabsContainer.addEventListener('click', (e) => { + if (e.target.classList.contains('tab')) { + + document.querySelectorAll('.tab').forEach(tab => { + tab.classList.remove('active'); + }); + document.querySelectorAll('.tab-content').forEach(content => { + content.classList.remove('active'); + }); + + e.target.classList.add('active'); + const contentId = e.target.getAttribute('data-tab'); + document.querySelector(contentId).classList.add('active'); + } + }); +}); \ No newline at end of file diff --git a/package.json b/package.json index 062605c..db6fa14 100644 --- a/package.json +++ b/package.json @@ -2,18 +2,22 @@ "name": "somethingidontknowabout", "private": true, "dependencies": { + "@mdn/browser-compat-data": "^5.6.33", "brotli-wasm": "^3.0.1", "fast-glob": "^3.3.3", - "tsup": "^8.3.5" + "pretty-ms": "^9.2.0", + "tsup": "^8.3.6" }, "devDependencies": { "@types/jquery": "^3.5.32", - "@types/node": "^22.10.7", + "@types/node": "^22.10.10", + "jscrewit": "^2.39.0", "typescript": "^5.7.3" }, "scripts": { "compress": "tsup --config tsup.config.js", - "compressWasm": "node compressWasm.cjs ./eagler-files/**/*.wasm" + "compressWasm": "node compressWasm.cjs ./eagler-files/**/*.wasm", + "compressMisc": "tsup --config tsup.config.misc.js" }, "type": "module" } \ No newline at end of file diff --git a/tsup.config.js b/tsup.config.js index a7dd9f2..d4fb6bb 100644 --- a/tsup.config.js +++ b/tsup.config.js @@ -1,10 +1,11 @@ import { defineConfig } from 'tsup'; import fg from 'fast-glob'; +import { target } from './getTsupTargets'; export default defineConfig({ entry: fg.globSync('eagler-files/**/*.js'), format: ['esm'], - target: ['chrome131'], + target, dts: false, clean: true, sourcemap: true, diff --git a/tsup.config.misc.js b/tsup.config.misc.js new file mode 100644 index 0000000..ababbef --- /dev/null +++ b/tsup.config.misc.js @@ -0,0 +1,28 @@ +import { defineConfig } from 'tsup'; +import fg from 'fast-glob'; +import { target } from './getTsupTargets.js'; + +export default defineConfig([ + { + entry: fg.globSync('dist-templates/**/*.js'), + format: 'esm', + target, + dts: false, + clean: true, + sourcemap: false, + minify: true, + watch: false, + outDir: 'dist-misc' + }, + { + entry: fg.globSync('js/*.js'), + format: 'esm', + target, + dts: false, + clean: true, + sourcemap: false, + minify: true, + watch: false, + outDir: 'dist-misc/js' + } +]); \ No newline at end of file