feat: add admin publishing workflow and yar theme
Add Go/Postgres admin APIs, Angular admin UI, manual build flow, asset uploads, markdown import/export, configurable slug generation, and the Yar reading theme. Exclude local docs and generated development artifacts from version control.
This commit is contained in:
parent
b78f4b39c9
commit
f0b50d13ea
121 changed files with 27139 additions and 550 deletions
117
frontend/admin/src/app/admin-api.service.ts
Normal file
117
frontend/admin/src/app/admin-api.service.ts
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
|
||||
import {
|
||||
AssetResponse,
|
||||
BuildJobResponse,
|
||||
LoginResponse,
|
||||
DeletePostResponse,
|
||||
PostInput,
|
||||
PostResponse,
|
||||
PostStatus,
|
||||
PostsResponse,
|
||||
SlugResponse
|
||||
} from './models';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AdminApiService {
|
||||
private readonly http = inject(HttpClient);
|
||||
private readonly baseUrl = '/api/admin';
|
||||
|
||||
me() {
|
||||
return this.http.get<{ user: LoginResponse['user'] }>(`${this.baseUrl}/me`, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
login(username: string, password: string) {
|
||||
return this.http.post<LoginResponse>(
|
||||
`${this.baseUrl}/login`,
|
||||
{ username, password },
|
||||
{ withCredentials: true }
|
||||
);
|
||||
}
|
||||
|
||||
logout() {
|
||||
return this.http.post<{ ok: boolean }>(`${this.baseUrl}/logout`, {}, { withCredentials: true });
|
||||
}
|
||||
|
||||
listPosts(status: PostStatus | '', limit?: number, offset?: number) {
|
||||
let params = new HttpParams();
|
||||
if (status) {
|
||||
params = params.set('status', status);
|
||||
}
|
||||
if (limit) {
|
||||
params = params.set('limit', String(limit));
|
||||
}
|
||||
if (offset) {
|
||||
params = params.set('offset', String(offset));
|
||||
}
|
||||
return this.http.get<PostsResponse>(`${this.baseUrl}/posts`, {
|
||||
params,
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
getPost(id: string) {
|
||||
return this.http.get<PostResponse>(`${this.baseUrl}/posts/${id}`, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
createPost(input: PostInput) {
|
||||
return this.http.post<PostResponse>(`${this.baseUrl}/posts`, input, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
updatePost(id: string, input: PostInput) {
|
||||
return this.http.put<PostResponse>(`${this.baseUrl}/posts/${id}`, input, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
deletePost(id: string) {
|
||||
return this.http.delete<DeletePostResponse>(`${this.baseUrl}/posts/${id}`, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
publishPost(id: string) {
|
||||
return this.http.post<PostResponse & BuildJobResponse>(
|
||||
`${this.baseUrl}/posts/${id}/publish`,
|
||||
{},
|
||||
{ withCredentials: true }
|
||||
);
|
||||
}
|
||||
|
||||
buildPost(id: string) {
|
||||
return this.http.post<BuildJobResponse>(
|
||||
`${this.baseUrl}/posts/${id}/build`,
|
||||
{},
|
||||
{ withCredentials: true }
|
||||
);
|
||||
}
|
||||
|
||||
getBuildJob(id: string) {
|
||||
return this.http.get<BuildJobResponse>(`${this.baseUrl}/build-jobs/${id}`, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
uploadAsset(file: File) {
|
||||
const body = new FormData();
|
||||
body.append('file', file);
|
||||
return this.http.post<AssetResponse>(`${this.baseUrl}/assets`, body, {
|
||||
withCredentials: true
|
||||
});
|
||||
}
|
||||
|
||||
generateSlug(title: string, summary: string, postId?: string) {
|
||||
return this.http.post<SlugResponse>(
|
||||
`${this.baseUrl}/slug`,
|
||||
{ title, summary, postId },
|
||||
{ withCredentials: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue