diff --git a/.env.example b/.env.example index 79a6c48..df221c8 100644 --- a/.env.example +++ b/.env.example @@ -15,7 +15,7 @@ GHOSTGUILD_REDIRECT_URI=https://wiki.ghostguild.org/api/auth/callback # Site Configuration SITE_URL=https://wiki.ghostguild.org SITE_NAME=Ghost Guild Knowledge Commons -SITE_DESCRIPTION=Collaborative knowledge base for the Baby Ghosts community +SITE_DESCRIPTION=A wiki for ghosts! 👻 # Forgejo Integration FORGEJO_URL=https://git.ghostguild.org @@ -43,4 +43,4 @@ SENTRY_ENVIRONMENT=production # Development NODE_ENV=development -DEBUG=false \ No newline at end of file +DEBUG=false diff --git a/app.config.ts b/app.config.ts new file mode 100644 index 0000000..fec1541 --- /dev/null +++ b/app.config.ts @@ -0,0 +1,65 @@ +export default defineAppConfig({ + ui: { + primary: 'blue', + gray: 'neutral', + + // Configure prose components + content: { + prose: { + // Base prose styling + prose: { + base: { + fontFamily: "'Crimson Text', Georgia, serif", + fontSize: '1.125rem', + lineHeight: '1.75', + maxWidth: 'none', + } + }, + // Paragraph styling + p: { + base: 'font-serif text-lg leading-relaxed mt-5 mb-5', + }, + // Heading styles + h1: { + base: 'font-serif font-bold text-4xl mt-8 mb-4', + }, + h2: { + base: 'font-serif font-semibold text-3xl mt-8 mb-4', + }, + h3: { + base: 'font-serif font-semibold text-2xl mt-6 mb-3', + }, + h4: { + base: 'font-serif font-semibold text-xl mt-6 mb-3', + }, + // List styling + ul: { + base: 'list-disc pl-6 my-5 space-y-2', + }, + ol: { + base: 'list-decimal pl-6 my-5 space-y-2', + }, + li: { + base: 'font-serif text-lg leading-relaxed', + }, + // Link styling + a: { + base: 'text-blue-600 underline hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300', + }, + // Blockquote styling + blockquote: { + base: 'border-l-4 border-gray-300 dark:border-gray-700 pl-4 my-5 italic font-serif', + }, + // Code styling + code: { + inline: { + base: 'bg-gray-100 dark:bg-gray-800 px-1 py-0.5 rounded text-sm font-mono', + }, + block: { + base: 'bg-gray-100 dark:bg-gray-800 p-4 rounded-lg overflow-x-auto my-5', + } + }, + } + } + } +}) diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 1bb45f7..a962528 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -1,49 +1,8 @@ +@import url("https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;0,700;1,400;1,600&display=swap"); @import "tailwindcss"; +@plugin "@tailwindcss/typography"; @layer components { - /* Custom prose styles */ - .prose { - @apply max-w-none; - } - - /* Article content styles */ - .article-content { - @apply max-w-none leading-relaxed; - } - - .article-content h1 { - @apply text-3xl font-bold mb-4 mt-6; - } - - .article-content h2 { - @apply text-2xl font-semibold mb-3 mt-8; - } - - .article-content h3 { - @apply text-xl font-semibold mb-2 mt-6; - } - - .article-content p { - @apply mb-4; - } - - .article-content ul, - .article-content ol { - @apply mb-4 ml-6; - } - - .article-content li { - @apply mb-2; - } - - .article-content code { - @apply bg-gray-100 dark:bg-gray-800 px-2 py-1 rounded text-sm font-mono; - } - - .article-content pre { - @apply bg-gray-100 dark:bg-gray-800 p-4 rounded-lg overflow-x-auto mb-4; - } - /* Editor styles */ .editor-container { @apply min-h-[500px] border rounded-lg; diff --git a/app/components/mdc/Alert.vue b/app/components/mdc/Alert.vue new file mode 100644 index 0000000..3102c95 --- /dev/null +++ b/app/components/mdc/Alert.vue @@ -0,0 +1,54 @@ + + + diff --git a/app/components/mdc/List.vue b/app/components/mdc/List.vue new file mode 100644 index 0000000..0f6589b --- /dev/null +++ b/app/components/mdc/List.vue @@ -0,0 +1,20 @@ + + + diff --git a/app/layouts/default.vue b/app/layouts/default.vue index d9e73b8..fc68faa 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -5,14 +5,24 @@
- - Wiki.GhostGuild + + Ghost Guild Wiki
- + Articles - + New Article
@@ -20,12 +30,21 @@
- {{ user?.displayName }} -
-
@@ -41,5 +60,5 @@ \ No newline at end of file +const { user, isAuthenticated, login, logout } = useAuth(); + diff --git a/app/pages/articles/[slug].vue b/app/pages/articles/[slug].vue index 09a9e88..82411dd 100644 --- a/app/pages/articles/[slug].vue +++ b/app/pages/articles/[slug].vue @@ -83,9 +83,10 @@
-
- -
+
{ - if (!article) return ""; - const candidate = - article.slug || - article.stem || - article._path || - article._id || - article.id || - ""; - const segments = candidate.split("/").filter(Boolean); - return segments[segments.length - 1] || ""; -}; - // Fetch article from Nuxt Content const { data: article, pending } = await useAsyncData( `article-${slug}`, async () => { + // Query for the specific article by stem (filename without extension) const articles = await queryCollection("articles").all(); - return articles.find((a) => getArticleSlug(a) === slug); + return articles.find((a) => a.stem === slug); }, ); diff --git a/app/pages/articles/index.vue b/app/pages/articles/index.vue index 8d7228d..6aa70ad 100644 --- a/app/pages/articles/index.vue +++ b/app/pages/articles/index.vue @@ -43,7 +43,9 @@ {{ article.title }} -

+

{{ article.description }}

@@ -117,20 +119,14 @@ const getArticleTitle = (article) => { // Resolve the correct Nuxt route for an article entry const getArticleSlug = (article) => { if (!article) return ""; - const candidate = - article.slug || - article.stem || - article._path || - article._id || - article.id || - ""; - const segments = candidate.split("/").filter(Boolean); - return segments[segments.length - 1] || ""; + // stem is the filename without extension + return article.stem || ""; }; const getArticlePath = (article) => { + if (!article) return "/articles"; const slug = getArticleSlug(article); - return slug ? `/articles/${slug}` : "/articles"; + return `/articles/${slug}`; }; // Filter and search articles diff --git a/app/pages/index.vue b/app/pages/index.vue index a2f0c1f..e911ec2 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,18 +1,13 @@