diff --git a/edu/index.html b/edu/index.html new file mode 100644 index 0000000..895d847 --- /dev/null +++ b/edu/index.html @@ -0,0 +1,145 @@ + + + + + + Open Learning Hub + + + +
+
+

Open Learning Hub

+

Your gateway to free educational resources across the web.

+
+
+ +
+
+

💡 Tip of the Day

+

Loading tip...

+ +
+ +
+

Educational Resources

+
+ + + + + + + +
+ +
+ +
+

freeCodeCamp

+

Learn to code for free with interactive lessons and projects.

+ Visit Site +
+
+

MDN Web Docs

+

Resources for developers, by developers. The bible of web dev.

+ Visit Site +
+
+

GitHub

+

The world's largest platform for software development and version control.

+ Visit Site +
+ + +
+

NASA

+

Explore the universe with images, videos, and news from NASA.

+ Visit Site +
+
+

National Geographic

+

World leader in geography, cartography and exploration.

+ Visit Site +
+
+

Nature

+

Leading international weekly journal of science.

+ Visit Site +
+ + +
+

Khan Academy

+

Free, world-class education for anyone, anywhere.

+ Visit Site +
+
+

Wolfram MathWorld

+

The web's most extensive mathematics resource.

+ Visit Site +
+
+

Desmos

+

Beautiful, free online graphing calculator.

+ Visit Site +
+ + +
+

Project Gutenberg

+

A library of over 60,000 free eBooks.

+ Visit Site +
+
+

Smithsonian

+

Official website of the Smithsonian Institution.

+ Visit Site +
+
+

Internet Archive

+

Non-profit library of millions of free books, movies, software, and music.

+ Visit Site +
+ + +
+

Duolingo

+

The world's most popular way to learn a language. It's 100% free.

+ Visit Site +
+
+

BBC Languages

+

Archived but excellent resources for learning 40 languages.

+ Visit Site +
+ + +
+

Coursera

+

Build skills with courses, certificates, and degrees online from world-class universities.

+ Visit Site +
+
+

edX

+

Access 2000+ free online courses from 140 leading institutions worldwide.

+ Visit Site +
+
+

MIT OpenCourseWare

+

A web-based publication of virtually all MIT course content.

+ Visit Site +
+
+
+
+ + + + + + diff --git a/edu/script.js b/edu/script.js new file mode 100644 index 0000000..c40d842 --- /dev/null +++ b/edu/script.js @@ -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'; + } + }); + }); + }); +}); diff --git a/edu/style.css b/edu/style.css new file mode 100644 index 0000000..c8b993a --- /dev/null +++ b/edu/style.css @@ -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; + } +} diff --git a/html/admin.html b/html/admin.html index 9067a88..28cf994 100755 --- a/html/admin.html +++ b/html/admin.html @@ -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)); + } + } @@ -57,6 +68,7 @@

admin page

+ diff --git a/index.js b/index.js index a01dc5b..f64a762 100755 --- a/index.js +++ b/index.js @@ -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) => { diff --git a/package-lock.json b/package-lock.json index 606eeed..5c2cd97 100755 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index b86917c..3c68549 100755 --- a/package.json +++ b/package.json @@ -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",