feat: major UI/UX overhaul, snippets system, and performance fixes
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 9m26s
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Failing after 9m26s
This commit is contained in:
78
scripts/setup-snippets.js
Normal file
78
scripts/setup-snippets.js
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
const fetch = require('node-fetch');
|
||||
require('dotenv').config();
|
||||
|
||||
const DIRECTUS_URL = process.env.DIRECTUS_URL || 'https://cms.dk0.dev';
|
||||
const DIRECTUS_TOKEN = process.env.DIRECTUS_STATIC_TOKEN;
|
||||
|
||||
async function setupSnippets() {
|
||||
console.log('📦 Setting up Snippets collection...');
|
||||
|
||||
// 1. Create Collection
|
||||
try {
|
||||
await fetch(`${DIRECTUS_URL}/collections`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
collection: 'snippets',
|
||||
meta: { icon: 'terminal', display_template: '{{title}}' },
|
||||
schema: { name: 'snippets' }
|
||||
})
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
// 2. Add Fields
|
||||
const fields = [
|
||||
{ field: 'status', type: 'string', meta: { interface: 'select-dropdown' }, schema: { default_value: 'published' } },
|
||||
{ field: 'title', type: 'string', meta: { interface: 'input' } },
|
||||
{ field: 'category', type: 'string', meta: { interface: 'input' } },
|
||||
{ field: 'code', type: 'text', meta: { interface: 'input-code' } },
|
||||
{ field: 'description', type: 'text', meta: { interface: 'textarea' } },
|
||||
{ field: 'language', type: 'string', meta: { interface: 'input' }, schema: { default_value: 'javascript' } },
|
||||
{ field: 'featured', type: 'boolean', meta: { interface: 'boolean' }, schema: { default_value: false } }
|
||||
];
|
||||
|
||||
for (const f of fields) {
|
||||
try {
|
||||
await fetch(`${DIRECTUS_URL}/fields/snippets`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(f)
|
||||
});
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 3. Add Example Data
|
||||
const exampleSnippets = [
|
||||
{
|
||||
title: 'Traefik SSL Config',
|
||||
category: 'Docker',
|
||||
language: 'yaml',
|
||||
featured: true,
|
||||
description: "Meine Standard-Konfiguration für automatisches SSL via Let's Encrypt in Docker Swarm.",
|
||||
code: "labels:\n - \"traefik.enable=true\"\n - \"traefik.http.routers.myapp.rule=Host(`example.com`)\"\n - \"traefik.http.routers.myapp.entrypoints=websecure\"\n - \"traefik.http.routers.myapp.tls.certresolver=myresolver\""
|
||||
},
|
||||
{
|
||||
title: 'Docker Cleanup Alias',
|
||||
category: 'ZSH',
|
||||
language: 'bash',
|
||||
featured: true,
|
||||
description: 'Ein einfacher Alias, um ungenutzte Docker-Container, Images und Volumes schnell zu entfernen.',
|
||||
code: "alias dclean='docker system prune -af --volumes'"
|
||||
}
|
||||
];
|
||||
|
||||
for (const s of exampleSnippets) {
|
||||
try {
|
||||
await fetch(`${DIRECTUS_URL}/items/snippets`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}`, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(s)
|
||||
});
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
console.log('✅ Snippets setup complete!');
|
||||
}
|
||||
|
||||
setupSnippets();
|
||||
162
scripts/update-hobbies.js
Normal file
162
scripts/update-hobbies.js
Normal file
@@ -0,0 +1,162 @@
|
||||
const fetch = require('node-fetch');
|
||||
require('dotenv').config();
|
||||
|
||||
const DIRECTUS_URL = process.env.DIRECTUS_URL || 'https://cms.dk0.dev';
|
||||
const DIRECTUS_TOKEN = process.env.DIRECTUS_STATIC_TOKEN;
|
||||
|
||||
async function syncHobbies() {
|
||||
const hobbies = [
|
||||
{
|
||||
key: 'gym',
|
||||
icon: 'Activity',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Gym', description: 'Bin wieder regelmäßig im Training.' },
|
||||
{ languages_code: 'en-US', title: 'Gym', description: 'Back at training regularly.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'skiing',
|
||||
icon: 'Activity',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Skifahren', description: 'Ich liebe es, auf der Piste zu sein.' },
|
||||
{ languages_code: 'en-US', title: 'Skiing', description: 'Love being out on the slopes.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'programming',
|
||||
icon: 'Code',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Programmieren', description: 'Mache ich einfach gerne, auch privat.' },
|
||||
{ languages_code: 'en-US', title: 'Programming', description: 'Just love building things, even in my free time.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'reading',
|
||||
icon: 'BookOpen',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Lesen', description: 'Lese einfach gerne zur Entspannung.' },
|
||||
{ languages_code: 'en-US', title: 'Reading', description: 'Enjoy reading to relax.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'gaming',
|
||||
icon: 'Gamepad2',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Zocken', description: 'Ab und zu mal eine Runde zocken.' },
|
||||
{ languages_code: 'en-US', title: 'Gaming', description: 'Playing some games every now and then.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'series',
|
||||
icon: 'Tv',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Serien', description: 'Ich schaue gerne gute Serien.' },
|
||||
{ languages_code: 'en-US', title: 'Series', description: 'I enjoy watching good series.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'boardgames',
|
||||
icon: 'Gamepad2',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Gesellschaftsspiele', description: 'Mag Gesellschaftsspiele mit Freunden.' },
|
||||
{ languages_code: 'en-US', title: 'Board Games', description: 'Love board games with friends.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'traveling',
|
||||
icon: 'Plane',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Reisen', description: 'Ich reise einfach gerne.' },
|
||||
{ languages_code: 'en-US', title: 'Traveling', description: 'I just love to travel.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'analog_photography',
|
||||
icon: 'Camera',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Analoge Fotografie', description: 'Lese mich gerade in das Thema ein.' },
|
||||
{ languages_code: 'en-US', title: 'Analog Photography', description: 'Currently reading into the topic.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'astronomy',
|
||||
icon: 'Stars',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Astronomie', description: 'Fasziniert vom Universum und Sternen.' },
|
||||
{ languages_code: 'en-US', title: 'Astronomy', description: 'Fascinated by the universe and stars.' }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'guitar',
|
||||
icon: 'Music',
|
||||
translations: [
|
||||
{ languages_code: 'de-DE', title: 'Gitarre', description: 'Spiele gelegentlich, wenn auch unregelmäßig.' },
|
||||
{ languages_code: 'en-US', title: 'Guitar', description: 'Playing occasionally, even if not regularly.' }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
console.log('🔄 Syncing hobbies to Directus...');
|
||||
|
||||
for (const hobby of hobbies) {
|
||||
try {
|
||||
const searchRes = await fetch(`${DIRECTUS_URL}/items/hobbies?filter[key][_eq]=${hobby.key}`, {
|
||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}` }
|
||||
});
|
||||
const searchData = await searchRes.json();
|
||||
|
||||
if (searchData.data && searchData.data.length > 0) {
|
||||
const id = searchData.data[0].id;
|
||||
console.log(`Updating ${hobby.key}...`);
|
||||
await fetch(`${DIRECTUS_URL}/items/hobbies/${id}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${DIRECTUS_TOKEN}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
status: 'published',
|
||||
icon: hobby.icon,
|
||||
translations: hobby.translations
|
||||
})
|
||||
});
|
||||
} else {
|
||||
console.log(`Creating ${hobby.key}...`);
|
||||
await fetch(`${DIRECTUS_URL}/items/hobbies`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${DIRECTUS_TOKEN}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
key: hobby.key,
|
||||
status: 'published',
|
||||
icon: hobby.icon,
|
||||
translations: hobby.translations
|
||||
})
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Failed to sync ${hobby.key}:`, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete 'gameServers' if it exists
|
||||
try {
|
||||
const delSearch = await fetch(`${DIRECTUS_URL}/items/hobbies?filter[key][_eq]=gameServers`, {
|
||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}` }
|
||||
});
|
||||
const delData = await delSearch.json();
|
||||
if (delData.data && delData.data.length > 0) {
|
||||
console.log('Removing gameServers hobby...');
|
||||
await fetch(`${DIRECTUS_URL}/items/hobbies/${delData.data[0].id}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${DIRECTUS_TOKEN}` }
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
console.log('✅ Done!');
|
||||
}
|
||||
|
||||
syncHobbies();
|
||||
Reference in New Issue
Block a user