Add database-backed bookmarks via GraphQL
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m47s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 3m47s
Replace hardcoded bookmarks in the frontend with a GORM-backed Bookmark model exposed through GraphQL query and admin-only create/delete mutations. Frontend groups bookmarks by category dynamically from the store. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
const rowingSessions = ref([]);
|
||||
const gitFeed = ref(null);
|
||||
const steamStatus = ref(null);
|
||||
const bookmarks = ref([]);
|
||||
const radioLive = ref(false);
|
||||
|
||||
async function fetchAll() {
|
||||
@@ -27,6 +28,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
activities { id type name link createdAt }
|
||||
spotifyRecent { track { name album { name images { url } } artists { name } } playedAt }
|
||||
rowingSessions { id date time distance timePer500m calories }
|
||||
bookmarks { id category name link }
|
||||
giteaFeed { avatarUrl repoUrl repoName opType commitMessage createdAt }
|
||||
steamStatus { online recentGames { appId name playtime2Weeks playtimeForever headerImageUrl } }
|
||||
me { id username admin }
|
||||
@@ -38,6 +40,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
favorites.value = data.favorites;
|
||||
activities.value = data.activities;
|
||||
spotifyRecent.value = data.spotifyRecent || [];
|
||||
bookmarks.value = data.bookmarks || [];
|
||||
rowingSessions.value = data.rowingSessions;
|
||||
gitFeed.value = data.giteaFeed || null;
|
||||
steamStatus.value = data.steamStatus || null;
|
||||
@@ -64,6 +67,7 @@ export const useHomeDataStore = defineStore("homeData", () => {
|
||||
loaded,
|
||||
error,
|
||||
me,
|
||||
bookmarks,
|
||||
posts,
|
||||
favorites,
|
||||
activities,
|
||||
|
||||
@@ -1,240 +1,18 @@
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
import LinkTable from "@/components/util/LinkTable.vue";
|
||||
import { useHomeDataStore } from "@/stores/homeData";
|
||||
|
||||
const links = [
|
||||
[
|
||||
"Reading Links",
|
||||
[
|
||||
{
|
||||
name: "Substack",
|
||||
link: "https://substack.com/",
|
||||
},
|
||||
{
|
||||
name: "Medium",
|
||||
link: "https://medium.com/",
|
||||
},
|
||||
{
|
||||
name: "4Chan",
|
||||
link: "https://www.4chan.org/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Job Links",
|
||||
[
|
||||
{
|
||||
name: "LinkedIn",
|
||||
link: "https://www.linkedin.com/",
|
||||
},
|
||||
{
|
||||
name: "Jack and Jill",
|
||||
link: "https://app.jackandjill.ai",
|
||||
},
|
||||
{
|
||||
name: "LinkedIn",
|
||||
link: "https://www.linkedin.com/",
|
||||
},
|
||||
{
|
||||
name: "Prospects",
|
||||
link: "https://www.prospects.ac.uk/",
|
||||
},
|
||||
{
|
||||
name: "GOV",
|
||||
link: "https://findajob.dwp.gov.uk",
|
||||
},
|
||||
{
|
||||
name: "Glassdoor",
|
||||
link: "https://www.glassdoor.co.uk/",
|
||||
},
|
||||
{
|
||||
name: "Indeed",
|
||||
link: "https://www.indeed.co.uk/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Learning Links",
|
||||
[
|
||||
{
|
||||
name: "Leetcode",
|
||||
link: "https://leetcode.com/",
|
||||
},
|
||||
{
|
||||
name: "ISLP",
|
||||
link: "https://hastie.su.domains/ISLP/ISLP_website.pdf.download.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Social Links",
|
||||
[
|
||||
{
|
||||
name: "Outlook",
|
||||
link: "https://outlook.live.com/",
|
||||
},
|
||||
{
|
||||
name: "Gmail",
|
||||
link: "https://mail.google.com/",
|
||||
},
|
||||
{
|
||||
name: "Whatsapp",
|
||||
link: "https://web.whatsapp.com/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Radio links",
|
||||
[
|
||||
{
|
||||
name: "Radio Helsinki",
|
||||
link: "https://www.radiohelsinki.fi/",
|
||||
},
|
||||
{
|
||||
name: "Palanga Street Radio",
|
||||
link: "https://palanga.live/",
|
||||
},
|
||||
{
|
||||
name: "IDA Radio",
|
||||
link: "https://idaidaida.net/",
|
||||
},
|
||||
{
|
||||
name: "Tīrkultūra",
|
||||
link: "https://www.tirkultura.lv/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Hacking Links",
|
||||
[
|
||||
{
|
||||
name: "pwn.college",
|
||||
link: "https://pwn.college/",
|
||||
},
|
||||
{
|
||||
name: "OSINT Framework",
|
||||
link: "https://osintframework.com/",
|
||||
},
|
||||
{
|
||||
name: "OverTheWire",
|
||||
link: "https://overthewire.org/",
|
||||
},
|
||||
{
|
||||
name: "TryHackMe",
|
||||
link: "https://tryhackme.com/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Chinese Links",
|
||||
[
|
||||
{
|
||||
name: "MDBG Chinese Dictionary",
|
||||
link: "https://www.mdbg.net/chinese/dictionary",
|
||||
},
|
||||
{
|
||||
name: "Stroke Order",
|
||||
link: "https://www.strokeorder.com/",
|
||||
},
|
||||
{
|
||||
name: "HSK 1 Peking University",
|
||||
link: "https://youtube.com/playlist?list=PLVWfp7qXLmKVfSUkucXErLncKn-JqgBbK&si=2ytO3inS8-iOAOx2",
|
||||
},
|
||||
{
|
||||
name: "Stroke Order",
|
||||
link: "https://www.strokeorder.com/",
|
||||
},
|
||||
{
|
||||
name: "Offbeat Mandarin",
|
||||
link: "https://www.youtube.com/@OffbeatMandarin",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Art links",
|
||||
[
|
||||
{
|
||||
name: "Frida Kahlo",
|
||||
link: "https://www.fridakahlo.org/",
|
||||
},
|
||||
{
|
||||
name: "Cameron's World",
|
||||
link: "https://www.cameronsworld.net/",
|
||||
},
|
||||
{
|
||||
name: "Neocities",
|
||||
link: "https://neocities.org/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Vue links",
|
||||
[
|
||||
{
|
||||
name: "Vue",
|
||||
link: "https://vuejs.org/guide/introduction.html",
|
||||
},
|
||||
{
|
||||
name: "Vue Router",
|
||||
link: "https://router.vuejs.org/introduction.html",
|
||||
},
|
||||
{
|
||||
name: "Pinia",
|
||||
link: "https://pinia.vuejs.org/introduction.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Go links",
|
||||
[
|
||||
{
|
||||
name: "Golang",
|
||||
link: "https://golang.org/doc/",
|
||||
},
|
||||
{
|
||||
name: "Gin Gonic",
|
||||
link: "https://gin-gonic.com/en/docs/introduction/",
|
||||
},
|
||||
{
|
||||
name: "GORM",
|
||||
link: "https://gorm.io/gen/index.html",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Doc links",
|
||||
[
|
||||
{
|
||||
name: "Rust",
|
||||
link: "https://doc.rust-lang.org/stable/book/index.html",
|
||||
},
|
||||
{
|
||||
name: "Javascript",
|
||||
link: "https://developer.mozilla.org/en-US/docs/Web/JavaScript",
|
||||
},
|
||||
{
|
||||
name: "Python",
|
||||
link: "https://docs.python.org/3/",
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
"Article links",
|
||||
[
|
||||
{
|
||||
name: "Go and GORM",
|
||||
link: "https://medium.com/@chaewonkong/learn-go-understanding-and-implementing-foreign-keys-with-gorm-6d7608e1dbf6",
|
||||
},
|
||||
{
|
||||
name: "JWT Auth in GO",
|
||||
link: "https://medium.com/monstar-lab-bangladesh-engineering/jwt-auth-in-go-dde432440924",
|
||||
},
|
||||
{
|
||||
name: "Websockets in GO",
|
||||
link: "https://medium.com/@tanngontn/golang-gin-framework-with-normal-websocket-and-websocket-with-producer-is-rabbitmq-guide-93cad7d290f7",
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
const homeData = useHomeDataStore();
|
||||
|
||||
const groupedBookmarks = computed(() => {
|
||||
const groups = {};
|
||||
for (const b of homeData.bookmarks) {
|
||||
if (!groups[b.category]) groups[b.category] = [];
|
||||
groups[b.category].push(b);
|
||||
}
|
||||
return Object.entries(groups);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -245,9 +23,9 @@ const links = [
|
||||
<div class="w-full h-fit">
|
||||
<LinkTable
|
||||
class="flex flex-col flex-wrap"
|
||||
v-for="link in links"
|
||||
:title="link[0]"
|
||||
:items="link[1]"
|
||||
v-for="group in groupedBookmarks"
|
||||
:title="group[0]"
|
||||
:items="group[1]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user