Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions orm/nuxt/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist

# Node dependencies
node_modules

# Logs
logs
*.log

# Misc
.DS_Store
.fleet
.idea

# Local env files
.env
.env.*
!.env.example
17 changes: 10 additions & 7 deletions orm/nuxt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,29 +174,32 @@ You can also access the REST API of the API server directly. It is running on th

### `GET`

- `/api/post/:id`: Fetch a single post by its `id`
- `/api/posts/:id`: Fetch a single post by its `id`
- `/api/feed`: Fetch all _published_ posts
- `/api/filterPosts?searchString={searchString}`: Filter posts by `title` or `content`
- `/api/drafts`: Fetch all _unpublished_ posts (drafts)

### `POST`

- `/api/post`: Create a new post
- `/api/posts`: Create a new post
- Body:
- `title: String` (required): The title of the post
- `content: String` (optional): The content of the post
- `authorEmail: String` (required): The email of the user that creates the post
- `/api/user`: Create a new user
- `/api/users`: Create a new user
- Body:
- `email: String` (required): The email address of the user
- `name: String` (optional): The name of the user
- `name: String` (required): The name of the user
- `/api/users/check`: Check if a user exists
- Body:
- `email: String` (required): The email address to check

### `PUT`

- `/api/publish/:id`: Publish a post by its `id`
- `/api/posts/:id/publish`: Publish a post by its `id`

### `DELETE`

- `/api/post/:id`: Delete a post by its `id`
- `/api/posts/:id`: Delete a post by its `id`

## Switch to another database (e.g. SQLite, MySQL, SQL Server, MongoDB)

Expand Down
9 changes: 3 additions & 6 deletions orm/nuxt/app/app.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<template>
<main>
<NuxtLayout name="default">
<NuxtPage/>
</NuxtLayout>
</main>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>

137 changes: 101 additions & 36 deletions orm/nuxt/app/components/Header.vue
Original file line number Diff line number Diff line change
@@ -1,51 +1,116 @@
<template>
<nav>
<div class="left">
<NuxtLink to="/"> Blog </NuxtLink>
<NuxtLink to="/drafts">Drafts</NuxtLink>
</div>
<div class="right">
<NuxtLink to="/signup">Signup</NuxtLink>
<NuxtLink to="/create">+ Create draft</NuxtLink>
<header class="header">
<div class="header-content">
<div class="logo">
<NuxtLink to="/" class="logo-link">
<span class="logo-icon">◇</span>
<span class="logo-text">Prisma Blog</span>
</NuxtLink>
</div>

<nav class="nav">
<NuxtLink to="/" class="nav-link" :class="{ active: route.path === '/' }">
Feed
</NuxtLink>
<NuxtLink to="/drafts" class="nav-link" :class="{ active: route.path === '/drafts' }">
Drafts
</NuxtLink>
</nav>

<div class="actions">
<NuxtLink to="/signup" class="btn btn-ghost">
Sign up
</NuxtLink>
<NuxtLink to="/create" class="btn btn-primary">
<span>+</span> New Post
</NuxtLink>
</div>
</div>
</nav>
</header>
</template>

<script setup>
<script setup lang="ts">
const route = useRoute()
</script>

<style scoped>
nav {
display: flex;
padding: 2rem;
align-items: center;
}
.header {
border-bottom: 1px solid var(--border-color);
backdrop-filter: blur(12px);
background: rgba(13, 17, 23, 0.8);
position: sticky;
top: 0;
z-index: 100;
}

.bold {
font-weight: bold;
}
.header-content {
max-width: 1200px;
margin: 0 auto;
padding: 1rem 2rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 2rem;
}

a {
text-decoration: none;
color: #000;
display: inline-block;
}
.logo-link {
display: flex;
align-items: center;
gap: 0.75rem;
color: var(--text-primary);
font-weight: 600;
font-size: 1.125rem;
}

.left a[data-active='true'] {
color: gray;
}
.logo-link:hover {
color: var(--text-primary);
}

a + a {
margin-left: 1rem;
}
.logo-icon {
font-size: 1.5rem;
color: var(--accent-primary);
}

.right {
margin-left: auto;
}
.nav {
display: flex;
gap: 0.5rem;
}

.nav-link {
padding: 0.5rem 1rem;
border-radius: var(--radius-sm);
color: var(--text-secondary);
font-weight: 500;
font-size: 0.9rem;
transition: all 0.2s;
}

.nav-link:hover {
color: var(--text-primary);
background: var(--bg-tertiary);
}

.nav-link.active {
color: var(--text-primary);
background: var(--bg-tertiary);
}

.right a {
border: 1px solid black;
padding: 0.5rem 1rem;
border-radius: 3px;
.actions {
display: flex;
gap: 0.75rem;
}

@media (max-width: 640px) {
.header-content {
padding: 1rem;
}

.logo-text {
display: none;
}

.nav {
display: none;
}
}
</style>
Loading
Loading