educational variant

This commit is contained in:
sky
2025-11-19 10:41:46 -05:00
parent 5045f30a4e
commit ef7c90840b
7 changed files with 455 additions and 0 deletions

145
edu/index.html Normal file
View File

@ -0,0 +1,145 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Open Learning Hub</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<div class="container">
<h1>Open Learning Hub</h1>
<p>Your gateway to free educational resources across the web.</p>
</div>
</header>
<main class="container">
<section id="tip-section">
<h2>💡 Tip of the Day</h2>
<p id="daily-tip">Loading tip...</p>
<button id="new-tip-btn">Get Another Tip</button>
</section>
<section id="resources">
<h2>Educational Resources</h2>
<div class="filter-controls">
<button class="filter-btn active" data-filter="all">All</button>
<button class="filter-btn" data-filter="coding">Coding</button>
<button class="filter-btn" data-filter="science">Science</button>
<button class="filter-btn" data-filter="math">Math</button>
<button class="filter-btn" data-filter="humanities">Humanities</button>
<button class="filter-btn" data-filter="languages">Languages</button>
<button class="filter-btn" data-filter="courses">Online Courses</button>
</div>
<div class="resource-grid">
<!-- Coding -->
<article class="card" data-category="coding">
<h3>freeCodeCamp</h3>
<p>Learn to code for free with interactive lessons and projects.</p>
<a href="https://www.freecodecamp.org" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="coding">
<h3>MDN Web Docs</h3>
<p>Resources for developers, by developers. The bible of web dev.</p>
<a href="https://developer.mozilla.org" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="coding">
<h3>GitHub</h3>
<p>The world's largest platform for software development and version control.</p>
<a href="https://github.com" target="_blank">Visit Site</a>
</article>
<!-- Science -->
<article class="card" data-category="science">
<h3>NASA</h3>
<p>Explore the universe with images, videos, and news from NASA.</p>
<a href="https://www.nasa.gov" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="science">
<h3>National Geographic</h3>
<p>World leader in geography, cartography and exploration.</p>
<a href="https://www.nationalgeographic.com" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="science">
<h3>Nature</h3>
<p>Leading international weekly journal of science.</p>
<a href="https://www.nature.com" target="_blank">Visit Site</a>
</article>
<!-- Math -->
<article class="card" data-category="math">
<h3>Khan Academy</h3>
<p>Free, world-class education for anyone, anywhere.</p>
<a href="https://www.khanacademy.org" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="math">
<h3>Wolfram MathWorld</h3>
<p>The web's most extensive mathematics resource.</p>
<a href="https://mathworld.wolfram.com" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="math">
<h3>Desmos</h3>
<p>Beautiful, free online graphing calculator.</p>
<a href="https://www.desmos.com" target="_blank">Visit Site</a>
</article>
<!-- Humanities -->
<article class="card" data-category="humanities">
<h3>Project Gutenberg</h3>
<p>A library of over 60,000 free eBooks.</p>
<a href="https://www.gutenberg.org" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="humanities">
<h3>Smithsonian</h3>
<p>Official website of the Smithsonian Institution.</p>
<a href="https://www.si.edu" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="humanities">
<h3>Internet Archive</h3>
<p>Non-profit library of millions of free books, movies, software, and music.</p>
<a href="https://archive.org" target="_blank">Visit Site</a>
</article>
<!-- Languages -->
<article class="card" data-category="languages">
<h3>Duolingo</h3>
<p>The world's most popular way to learn a language. It's 100% free.</p>
<a href="https://www.duolingo.com" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="languages">
<h3>BBC Languages</h3>
<p>Archived but excellent resources for learning 40 languages.</p>
<a href="https://www.bbc.co.uk/languages/" target="_blank">Visit Site</a>
</article>
<!-- Online Courses -->
<article class="card" data-category="courses">
<h3>Coursera</h3>
<p>Build skills with courses, certificates, and degrees online from world-class universities.</p>
<a href="https://www.coursera.org" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="courses">
<h3>edX</h3>
<p>Access 2000+ free online courses from 140 leading institutions worldwide.</p>
<a href="https://www.edx.org" target="_blank">Visit Site</a>
</article>
<article class="card" data-category="courses">
<h3>MIT OpenCourseWare</h3>
<p>A web-based publication of virtually all MIT course content.</p>
<a href="https://ocw.mit.edu" target="_blank">Visit Site</a>
</article>
</div>
</section>
</main>
<footer>
<div class="container">
<p>&copy; 2025 Open Learning Hub.</p>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>

65
edu/script.js Normal file
View File

@ -0,0 +1,65 @@
document.addEventListener('DOMContentLoaded', () => {
// --- Tip of the Day Logic ---
const tips = [
"Spaced repetition is a learning technique that incorporates increasing intervals of time between subsequent review of previously learned material.",
"The Pomodoro Technique uses a timer to break down work into intervals, traditionally 25 minutes in length, separated by short breaks.",
"Teaching someone else is one of the best ways to learn a new concept (The Feynman Technique).",
"Sleep is crucial for memory consolidation. Pulling an all-nighter is often counterproductive.",
"Active recall (testing yourself) is far more effective than passive re-reading.",
"Interleaving practice (mixing different subjects or topics) improves long-term retention compared to blocked practice.",
"Exercise increases blood flow to the brain and can improve cognitive performance.",
"Setting specific, measurable goals (SMART goals) helps maintain motivation.",
"Taking handwritten notes can improve conceptual understanding better than typing.",
"Mnemonic devices like acronyms or rhymes can help encode information into long-term memory."
];
const tipElement = document.getElementById('daily-tip');
const newTipBtn = document.getElementById('new-tip-btn');
function showRandomTip() {
const randomIndex = Math.floor(Math.random() * tips.length);
tipElement.textContent = tips[randomIndex];
// Add a subtle animation effect
tipElement.style.opacity = 0;
setTimeout(() => {
tipElement.style.opacity = 1;
}, 50);
}
if (newTipBtn) {
newTipBtn.addEventListener('click', showRandomTip);
}
// Show initial tip
if (tipElement) {
showRandomTip();
tipElement.style.transition = "opacity 0.5s ease-in-out";
}
// --- Filtering Logic ---
const filterBtns = document.querySelectorAll('.filter-btn');
const cards = document.querySelectorAll('.card');
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
// Remove active class from all buttons
filterBtns.forEach(b => b.classList.remove('active'));
// Add active class to clicked button
btn.classList.add('active');
const filterValue = btn.getAttribute('data-filter');
cards.forEach(card => {
if (filterValue === 'all' || card.getAttribute('data-category') === filterValue) {
card.style.display = 'flex';
// Add animation for appearing elements
card.style.animation = 'fadeIn 0.5s ease-in-out';
} else {
card.style.display = 'none';
}
});
});
});
});

166
edu/style.css Normal file
View File

@ -0,0 +1,166 @@
:root {
--primary-color: #2c3e50;
--secondary-color: #3498db;
--accent-color: #e74c3c;
--bg-color: #f4f4f4;
--card-bg: #ffffff;
--text-color: #333;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
background-color: var(--bg-color);
color: var(--text-color);
}
.container {
max-width: 1100px;
margin: 0 auto;
padding: 0 20px;
}
header {
background-color: var(--primary-color);
color: white;
padding: 2rem 0;
text-align: center;
margin-bottom: 2rem;
}
header h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
}
section {
margin-bottom: 3rem;
}
h2 {
color: var(--primary-color);
border-bottom: 2px solid var(--secondary-color);
padding-bottom: 0.5rem;
margin-bottom: 1.5rem;
display: inline-block;
}
/* Tip Section */
#tip-section {
background-color: var(--card-bg);
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
border-left: 5px solid var(--accent-color);
}
#new-tip-btn {
background-color: var(--secondary-color);
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin-top: 1rem;
transition: background 0.3s;
}
#new-tip-btn:hover {
background-color: #2980b9;
}
/* Filter Controls */
.filter-controls {
margin-bottom: 1.5rem;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.filter-btn {
background: transparent;
border: 2px solid var(--secondary-color);
color: var(--secondary-color);
padding: 6px 12px;
border-radius: 20px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s;
}
.filter-btn:hover, .filter-btn.active {
background-color: var(--secondary-color);
color: white;
}
/* Resource Grid */
.resource-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
}
.card {
background-color: var(--card-bg);
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
transition: transform 0.2s;
display: flex;
flex-direction: column;
}
.card:hover {
transform: translateY(-5px);
}
.card h3 {
margin-bottom: 0.5rem;
color: var(--primary-color);
}
.card p {
flex-grow: 1;
margin-bottom: 1rem;
color: #666;
}
.card a {
display: inline-block;
text-decoration: none;
color: var(--secondary-color);
font-weight: bold;
}
.card a:hover {
text-decoration: underline;
}
footer {
text-align: center;
padding: 2rem 0;
margin-top: 2rem;
color: #777;
border-top: 1px solid #ddd;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 600px) {
header h1 {
font-size: 2rem;
}
.resource-grid {
grid-template-columns: 1fr;
}
}

View File

@ -50,6 +50,17 @@
}
}
}
function setRecat() {
let domain = prompt("domain");
if(domain) {
fetch("/api/recat", {
method: "POST",
body: JSON.stringify({domain: domain})
})
.then(data => data.text())
.then(data => alert(data));
}
}
</script>
</head>
<alerts> </alerts>
@ -57,6 +68,7 @@
<h1 class="title">admin page</h1>
<sections>
<button onclick="sendAnnouncement()">send announcement</button>
<button onclick="setRecat()">set a domain to recat</button>
</sections>
</body>
</html>

View File

@ -17,9 +17,22 @@ import { getRawData, generateAccountPage, editProfile, saveData, getUsers, isAdm
import { callAI } from "./ai.js";
import { Readable } from 'stream';
import os from "node:os";
import chokidar from 'chokidar';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
let recatters = JSON.parse(await fs.readFile("./data/recats.json"));
const watcher = chokidar.watch('./data/recats.json', {
persistent: true,
awaitWriteFinish: {
stabilityThreshold: 500,
pollInterval: 100
}
});
watcher.on('change', async (event, filePath) => {
recatters = JSON.parse(await fs.readFile("./data/recats.json"));
});
await findClientID();
setInterval(async () => {
await findClientID();
@ -28,6 +41,15 @@ setInterval(async () => {
const port = process.env.PORT || 3000;
const app = express();
let recatFolder = express.static("./edu", { extensions: ["html"] });
app.use((req, res, next) => {
if(recatters.includes(req.hostname)) {
return recatFolder(req, res, next);
}
next();
});
// why the fuck does this have to exist?
app.use("/resources/semag/hotline-miami/", (req,res,next) => {
if(req.method == "HEAD") {
@ -186,6 +208,21 @@ app.use("/api/music/download", async (req, res, next) => {
}
res.end();
});
app.post("/api/recat", async (req, res) => {
if(isAdmin(req.cookies.token)) {
let domain = JSON.parse(req.body)["domain"];
let message;
if(recatters.includes(domain)) {
recatters.pop(domain);
message = `Successfully set ${domain} to Selenite.`
} else {
recatters.push(domain);
message = `Successfully set ${domain} as educational.`
}
fs.writeFile("./data/recats.json", JSON.stringify(recatters));
res.send(message);
};
})
// friends endpoints
app.get("/api/friends/list", async (req, res) => {

29
package-lock.json generated
View File

@ -14,6 +14,7 @@
"axios": "^1.12.2",
"body-parser": "^2.2.0",
"chalk": "^5.6.2",
"chokidar": "^4.0.3",
"compression": "^1.8.1",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
@ -727,6 +728,21 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/color": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
@ -1905,6 +1921,19 @@
"node": ">= 0.8"
}
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",

View File

@ -18,6 +18,7 @@
"axios": "^1.12.2",
"body-parser": "^2.2.0",
"chalk": "^5.6.2",
"chokidar": "^4.0.3",
"compression": "^1.8.1",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",