just gonna push this before massively redesigning the popup modal under preston's recruitment

This commit is contained in:
quartinal 2025-01-25 17:28:22 -08:00
parent 804067db06
commit 76272b26a1
14 changed files with 758 additions and 206 deletions

2
.gitignore vendored
View File

@ -1,7 +1,9 @@
dist/ dist/
dist-misc/
node_modules/ node_modules/
pnpm-lock.yaml pnpm-lock.yaml
.vercel .vercel
# Local Netlify folder # Local Netlify folder
.netlify .netlify
.idea/

View File

@ -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. > 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] > [!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] > [!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. > 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.

View File

@ -1,17 +1,16 @@
/* General Styles */ /* General Styles */
body { body {
font-family: 'Arial', sans-serif; font-family: 'Raleway', sans-serif;
background-color: var(--ctp-macchiato-overlay0); background-color: var(--ctp-macchiato-overlay0);
background-size: auto;
margin: 0; margin: 0;
padding: 0; padding: 0;
text-align: center;
display: flex;
flex-direction: column;
min-height: 100vh; min-height: 100vh;
overflow-x: hidden; overflow-x: hidden;
color: var(--ctp-macchiato-mantle); 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 { body.dark-mode {
@ -22,88 +21,193 @@ body.dark-mode {
header { header {
background-color: var(--ctp-macchiato-green); background-color: var(--ctp-macchiato-green);
color: var(--ctp-macchiato-crust); color: var(--ctp-macchiato-crust);
padding: 20px 0; padding: 1.5rem 0;
text-align: center; transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
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);
} }
header h1 { header h1 {
margin: 0; margin: 0;
transform: translateY(0);
transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
header h1:hover {
transform: translateY(-2px);
} }
main { main {
flex: 1; display: grid;
padding: 20px; gap: 2rem;
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
width: 100%;
place-items: center;
} }
.darkmodediv { .darkmodediv {
padding-left: 480px; padding: 1rem;
padding-right: 480px;
background: var(--ctp-macchiato-rosewater); background: var(--ctp-macchiato-rosewater);
} border-radius: 8px;
margin: 0 auto;
.counter, .info, .clients, .danger-zone { max-width: 800px;
margin-bottom: 20px; width: 100%;
} }
.Container18, .Container15, .ContainerOther { .Container18, .Container15, .ContainerOther {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
gap: 40px; align-items: center;
margin: 20px 0; 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 { button, .source-btn, .dsc-btn, .clr-btn {
background-color: var(--ctp-macchiato-green); background-color: var(--ctp-macchiato-green);
color: var(--ctp-macchiato-mantle); color: var(--ctp-macchiato-mantle);
padding: 10px 20px; padding: 0.75rem 1.5rem;
font-size: 16px; font-size: 1rem;
cursor: pointer; cursor: pointer;
border: none; border: none;
border-radius: 5px; border-radius: 8px;
text-decoration: none; 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 { /* GSAP-like animations only for regular buttons */
background-color: var(--ctp-macchiato-green); 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 { 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 { button:active {
outline: 3px solid var(--ctp-macchiato-overlay2); transform: scale(0.95);
outline-offset: 2px; transition-duration: 0.1s;
} }
.clr-btn:hover { /* Simple transitions for dsc-btn and clr-btn */
background-color: var(--ctp-macchiato-peach); .dsc-btn, .clr-btn {
transform: scale(+1.14) translateX(-20px); transition: background-color 0.3s ease;
}
.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 */
} }
.dsc-btn { .dsc-btn {
background-color: var(--ctp-macchiato-crust); background-color: var(--ctp-macchiato-mauve);
color: var(--ctp-macchiato-lavender);
transition: 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55);
} }
.clr-btn { .clr-btn {
@ -111,183 +215,148 @@ button:focus {
} }
.search-container { .search-container {
margin: 20px 0; display: grid;
place-items: center;
gap: 1rem;
margin: 2rem 0;
width: 100%;
} }
#search-bar { #search-bar {
background-color: var(--ctp-macchiato-mantle); background-color: var(--ctp-macchiato-mantle);
padding: 10px; padding: 1rem 1.5rem;
border-radius: 35px; border-radius: 999px;
width: 50%; width: 100%;
max-width: 500px;
outline: none; outline: none;
border: 4px solid var(--ctp-macchiato-green); border: 3px solid var(--ctp-macchiato-green);
color: var(--ctp-macchiato-text); color: var(--ctp-macchiato-text);
transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
} }
#search-bar:focus { #search-bar:focus {
border-width: 5px; border-width: 4px;
} transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
#search-bar::placeholder {
color: var(--ctp-macchiato-text);
} }
.footer { .footer {
display: flex; display: grid;
justify-content: center; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
align-items: center; gap: 2rem;
gap: 40px; padding: 1.5rem;
background-color: var(--ctp-macchiato-overlay1); background-color: var(--ctp-macchiato-overlay1);
color: var(--ctp-macchiato-mantle); /* Light text color for footer */ color: var(--ctp-macchiato-text);
padding: 10px; place-items: center;
text-align: center; transition: all 0.6s cubic-bezier(0.16, 1, 0.3, 1);
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);
} }
.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 { .modal {
display: none; display: none;
position: fixed; position: fixed;
z-index: 1; inset: 0;
left: 0; background-color: rgba(0, 0, 0, 0.5);
top: 0; place-items: center;
width: 100%; backdrop-filter: blur(4px);
height: 100%;
background-color: var(--ctp-macchiato-mantle);
justify-content: center;
align-items: center;
} }
.modal-content { .modal-content {
background-color: var(--ctp-macchiato-text); background-color: var(--ctp-macchiato-text);
padding: 20px; padding: 2rem;
border-radius: 10px; border-radius: 12px;
width: 80%; width: 90%;
max-width: 400px; max-width: 500px;
text-align: center; display: grid;
box-shadow: 0px 4px 8px var(--ctp-macchiato-mantle); gap: 1.5rem;
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); 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 { /* Source button with minimal animation */
color: var(--ctp-macchiato-surface1); .source-btn {
background-color: var(--ctp-macchiato-mantle);
transition: background-color 0.3s ease;
} }
.modal p { /* Dark Mode enhancements */
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 */
body.dark-mode .modal-content { body.dark-mode .modal-content {
background-color: var(--ctp-macchiato-mantle); background-color: var(--ctp-macchiato-mantle);
color: var(--ctp-macchiato-text); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
body.dark-mode .modal h2 {
color: var(--ctp-macchiato-text);
}
body.dark-mode .modal p {
color: var(--ctp-macchiato-text);
} }
body.dark-mode #search-bar { body.dark-mode #search-bar {
background-color: var(--ctp-macchiato-overlay0); background-color: var(--ctp-macchiato-overlay0);
color: var(--ctp-macchiato-text); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
border-color: var(--ctp-macchiato-overlay1);
}
body.dark-mode #search-bar:focus {
border-color: var(--ctp-macchiato-green);
} }
body.dark-mode .footer { body.dark-mode .footer {
background-color: var(--ctp-macchiato-overlay0); /* Dark gray color for footer in dark mode */ background-color: var(--ctp-macchiato-overlay0);
color: var(--ctp-macchiato-text); /* Light text color for footer in dark mode */ border-top: 1px solid var(--ctp-macchiato-overlay1);
} }
body.dark-mode .footer a { /* Responsive centering for smaller screens */
color: var(--ctp-macchiato-text); /* Light text color for footer links in dark mode */ @media (max-width: 768px) {
.Container18, .Container15, .ContainerOther {
grid-template-columns: 1fr;
max-width: 400px;
margin: 0 auto;
} }
body.dark-mode .footer button.server-list { .darkmodediv {
background-color: var(--ctp-macchiato-crust); /* Black color for Server List button in dark mode */ padding: 1rem;
margin: 0 1rem;
}
} }
body.dark-mode .footer button.server-list:hover { /* Tabs styling */
background-color: var(--ctp-macchiato-overlay1); /* Slightly lighter shade for hover effect in dark mode */ .tabs {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 2rem;
padding: 0 1rem;
} }
body.dark-mode .footer button.eaglerrinth-mod-list { .tab {
background-color: var(--ctp-macchiato-mauve); /* Same color as Discord link button in dark mode */ 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:hover { .tab.active {
filter: brightness(1.2); /* Slightly lighter shade for hover effect in dark mode */ 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);
}
.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 */
} }

View File

@ -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(
`
<div class="performance-popover-section">
<h2>Whoops!</h2>
<p>Looks like <span>${location.host}</span> loaded slower than usual!</p>
<p>Precisely, it loaded in ${prettifiedLoadTime}.</p>
<p data-question-anchor>
Do you want to <a data-one>turn off script obfuscation</a> or <a data-two>continue</a>?
</p>
</div>
`
);
const styleSheet = document.createElement('style');
document.head.appendChild(styleSheet);
const { sheet } = styleSheet;
const rulesLength = sheet.cssRules.length;
}
});
}

View File

@ -0,0 +1 @@
export { default as default } from 'pretty-ms';

View File

@ -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));
}
};

28
getTsupTargets.js Normal file
View File

@ -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();

View File

@ -9,6 +9,7 @@
<link rel="icon" type="image/x-icon" href="images/eaglercommunity.png"> <link rel="icon" type="image/x-icon" href="images/eaglercommunity.png">
<link rel="stylesheet" href="./css/styles.css"> <link rel="stylesheet" href="./css/styles.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@catppuccin/palette/css/catppuccin.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@catppuccin/palette/css/catppuccin.min.css">
<link href="https://fonts.googleapis.com/css2?family=Raleway:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script async src="https://cdn.jsdelivr.net/npm/es-module-shims"></script> <script async src="https://cdn.jsdelivr.net/npm/es-module-shims"></script>
<script type="importmap"> <script type="importmap">
@ -22,12 +23,14 @@
<script defer src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script defer src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/eruda"></script> <script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script defer async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2593894696548093" crossorigin="anonymous"></script> <script defer async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2593894696548093" crossorigin="anonymous"></script>
<script type="module-shim" src="js/darkmode.js"></script> <script type="module" src="js/main.js"></script>
<script type="module" src="js/darkmode.js"></script>
<script type="module" src="js/ga4.js"></script> <script type="module" src="js/ga4.js"></script>
<script type="module-shim" src="js/main.js"></script>
<script type="module" src="js/popupPrompt.js"></script> <script type="module" src="js/popupPrompt.js"></script>
<script type="module" src="js/tabs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bowser"></script> <script src="https://cdn.jsdelivr.net/npm/bowser"></script>
<script src="https://cdn.jsdelivr.net/npm/fuse.js"></script> <script src="https://cdn.jsdelivr.net/npm/fuse.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify"></script>
<meta property="og:title" content="Eaglercraft Client Collections"> <meta property="og:title" content="Eaglercraft Client Collections">
<meta property="og:type" content="website"> <meta property="og:type" content="website">
@ -71,8 +74,6 @@
<div class="clientbutton"> <div class="clientbutton">
<section class="clients"> <section class="clients">
<h2 class="pick-client">Pick a Client:</h2> <h2 class="pick-client">Pick a Client:</h2>
<label for="showModded">Show Modded Clients</label>
<input type="checkbox" id="showModded">
<div class="search-container"> <div class="search-container">
<input type="text" id="search-bar" placeholder="Search Clients..."> <input type="text" id="search-bar" placeholder="Search Clients...">
</div> </div>

View File

@ -6,8 +6,6 @@ import {
selectTag, selectTag,
} from "./helperFunctions.js"; } from "./helperFunctions.js";
global.querySelectorAll = document.querySelectorAll;
$(function() { $(function() {
function applyStyles(elements, styles) { function applyStyles(elements, styles) {
elements.forEach(element => pushStyles(element, styles)); elements.forEach(element => pushStyles(element, styles));
@ -20,13 +18,12 @@ $(function() {
color: hexToRGB('#f1f1f1') color: hexToRGB('#f1f1f1')
} : { } : {
backgroundColor: '#f1f1f1', backgroundColor: '#f1f1f1',
color: 'black', color: 'var(--ctp-macchiato-mantle)',
backgroundImage: "url('/images/grass-background.jpg')" backgroundImage: "url('/images/grass-background.jpg')"
}; };
pushStyles(body, commonStyles); pushStyles(body, commonStyles);
applyStyles(document.querySelectorAll('p'), { color: commonStyles.color });
applyStyles([selectTag('h2'), selectTag('h1')], { color: commonStyles.color }); applyStyles([selectTag('h2'), selectTag('h1')], { color: commonStyles.color });
if (isChecked) { if (isChecked) {

View File

@ -61,9 +61,13 @@ $(function() {
} }
} }
function updateShowModded() { // fix something very absurd
toggleVisibility("#moddedButtons", $("#showModded").is(":checked")); window.addEventListener('load', () => {
if (!($('#darkModeCheckbox').is(':checked'))) {
$('.footer p').removeAttr('style');
$('.footer p').css('color', 'var(--ctp-macchiato-text)');
} }
});
$("#darkModeCheckbox").on("change", updateDarkMode); $("#darkModeCheckbox").on("change", updateDarkMode);
updateDarkMode(); updateDarkMode();
@ -71,7 +75,4 @@ $(function() {
selectId('clr-data-modal').addEventListener('click', handleClrModalClick); selectId('clr-data-modal').addEventListener('click', handleClrModalClick);
$('#search-bar').on('keyup', handleSearchBarKeyup); $('#search-bar').on('keyup', handleSearchBarKeyup);
$("#showModded").on("change", updateShowModded);
updateShowModded();
}); });

48
js/tabs.js Normal file
View File

@ -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');
}
});
});

View File

@ -2,18 +2,22 @@
"name": "somethingidontknowabout", "name": "somethingidontknowabout",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@mdn/browser-compat-data": "^5.6.33",
"brotli-wasm": "^3.0.1", "brotli-wasm": "^3.0.1",
"fast-glob": "^3.3.3", "fast-glob": "^3.3.3",
"tsup": "^8.3.5" "pretty-ms": "^9.2.0",
"tsup": "^8.3.6"
}, },
"devDependencies": { "devDependencies": {
"@types/jquery": "^3.5.32", "@types/jquery": "^3.5.32",
"@types/node": "^22.10.7", "@types/node": "^22.10.10",
"jscrewit": "^2.39.0",
"typescript": "^5.7.3" "typescript": "^5.7.3"
}, },
"scripts": { "scripts": {
"compress": "tsup --config tsup.config.js", "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" "type": "module"
} }

View File

@ -1,10 +1,11 @@
import { defineConfig } from 'tsup'; import { defineConfig } from 'tsup';
import fg from 'fast-glob'; import fg from 'fast-glob';
import { target } from './getTsupTargets';
export default defineConfig({ export default defineConfig({
entry: fg.globSync('eagler-files/**/*.js'), entry: fg.globSync('eagler-files/**/*.js'),
format: ['esm'], format: ['esm'],
target: ['chrome131'], target,
dts: false, dts: false,
clean: true, clean: true,
sourcemap: true, sourcemap: true,

28
tsup.config.misc.js Normal file
View File

@ -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'
}
]);