ui redesign, markdown fix + metadata and auth header
This commit is contained in:
+20
-13
@@ -1,25 +1,19 @@
|
||||
import type { Post, SiteConfig, Asset } from './types';
|
||||
|
||||
function getToken(): string | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
return localStorage.getItem('admin_token');
|
||||
}
|
||||
|
||||
async function apiFetch<T>(path: string, options: RequestInit = {}): Promise<T> {
|
||||
const headers: Record<string, string> = {
|
||||
...(options.headers as Record<string, string> || {}),
|
||||
};
|
||||
|
||||
const token = getToken();
|
||||
if (token) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
if (!(options.body instanceof FormData)) {
|
||||
headers['Content-Type'] = headers['Content-Type'] || 'application/json';
|
||||
}
|
||||
|
||||
const res = await fetch(`/api${path}`, { ...options, headers });
|
||||
const res = await fetch(`/api${path}`, {
|
||||
...options,
|
||||
headers,
|
||||
credentials: 'same-origin',
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const body = await res.json().catch(() => ({}));
|
||||
@@ -37,11 +31,24 @@ export class ApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// Auth
|
||||
export const login = (token: string) =>
|
||||
apiFetch<void>('/auth/login', { method: 'POST', body: JSON.stringify({ token }) });
|
||||
export const logout = () => apiFetch<void>('/auth/logout', { method: 'POST' });
|
||||
export const checkSession = () => apiFetch<void>('/auth/me');
|
||||
|
||||
// Posts
|
||||
export const getPosts = () => apiFetch<Post[]>('/posts');
|
||||
export const getPost = (slug: string) => apiFetch<Post>(`/posts/${encodeURIComponent(slug)}`);
|
||||
export const savePost = (data: { slug: string; old_slug?: string | null; summary?: string | null; content: string }) =>
|
||||
apiFetch<Post>('/posts', { method: 'POST', body: JSON.stringify(data) });
|
||||
export const savePost = (data: {
|
||||
slug: string;
|
||||
old_slug?: string | null;
|
||||
date?: string;
|
||||
summary?: string | null;
|
||||
tags?: string[];
|
||||
draft?: boolean;
|
||||
content: string;
|
||||
}) => apiFetch<Post>('/posts', { method: 'POST', body: JSON.stringify(data) });
|
||||
export const deletePost = (slug: string) =>
|
||||
apiFetch<void>(`/posts/${encodeURIComponent(slug)}`, { method: 'DELETE' });
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Marked } from 'marked';
|
||||
import markedKatex from 'marked-katex-extension';
|
||||
import { markedHighlight } from 'marked-highlight';
|
||||
import { gfmHeadingId } from 'marked-gfm-heading-id';
|
||||
import hljs from 'highlight.js';
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
|
||||
const renderer = new Marked()
|
||||
.setOptions({ gfm: true, breaks: false })
|
||||
.use(gfmHeadingId())
|
||||
.use(
|
||||
markedHighlight({
|
||||
langPrefix: 'hljs language-',
|
||||
highlight(code, lang) {
|
||||
const language = lang && hljs.getLanguage(lang) ? lang : 'plaintext';
|
||||
return hljs.highlight(code, { language }).value;
|
||||
},
|
||||
}),
|
||||
)
|
||||
.use(markedKatex({ throwOnError: false, nonStandard: true }));
|
||||
|
||||
const KATEX_TAGS = [
|
||||
'math', 'annotation', 'semantics', 'mrow', 'mi', 'mo', 'mn', 'mtext',
|
||||
'msup', 'msub', 'msubsup', 'mfrac', 'msqrt', 'mroot', 'mover', 'munder',
|
||||
'munderover', 'mtable', 'mtr', 'mtd', 'mspace', 'mstyle', 'mphantom',
|
||||
'mpadded', 'menclose',
|
||||
];
|
||||
|
||||
export function renderMarkdown(src: string): string {
|
||||
const html = renderer.parse(src, { async: false }) as string;
|
||||
return DOMPurify.sanitize(html, {
|
||||
ADD_TAGS: KATEX_TAGS,
|
||||
ADD_ATTR: ['aria-hidden', 'style', 'id', 'class', 'encoding', 'mathvariant', 'displaystyle', 'scriptlevel'],
|
||||
});
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
export interface Post {
|
||||
slug: string;
|
||||
date: string;
|
||||
content: string;
|
||||
summary?: string;
|
||||
excerpt?: string;
|
||||
tags: string[];
|
||||
draft: boolean;
|
||||
reading_time: number;
|
||||
}
|
||||
|
||||
export interface SiteConfig {
|
||||
|
||||
Reference in New Issue
Block a user