Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7044ecf
Update comments UI : Replace 2‑level comment threading with a recursi…
raynaldlao Jul 7, 2026
07e13f7
Update comments UI : Sanitize comment HTML with nh3 to block XSS: str…
raynaldlao Jul 7, 2026
7b82ead
Update comments UI : Introduce recursive render_comment(node, depth=0…
raynaldlao Jul 7, 2026
b362062
Update comments UI : Add N‑level comment threading CSS with .comment,…
raynaldlao Jul 7, 2026
f7a7b98
Update comments UI : Integrate SunEditor for comments by replacing th…
raynaldlao Jul 7, 2026
c1be167
Update comments UI : Soft‑delete keeps deleted comments in the thread…
raynaldlao Jul 7, 2026
f91f9cc
Update comments UI : Adds an emoji picker to the SunEditor toolbar. T…
raynaldlao Jul 7, 2026
8019017
Update comments UI : Improves emoji picker positioning and scroll beh…
raynaldlao Jul 7, 2026
d545f3a
Update comments UI : Disables the skin‑tone selector in the comment e…
raynaldlao Jul 7, 2026
5eeeb99
Update comments UI : Applies the blog’s Inter font to the emoji picke…
raynaldlao Jul 7, 2026
f344a96
Update comments UI : Adds toggle behavior to the emoji picker. Clicki…
raynaldlao Jul 7, 2026
b4ca21a
Update comments UI : Applies the blog’s Inter font to the entire SunE…
raynaldlao Jul 7, 2026
bf9df5c
Update comments UI : Fixes SunEditor dark theme, font, spacing and st…
raynaldlao Jul 8, 2026
201458c
Update comments UI : Fixes SunEditor dark‑mode styling for toolbar ic…
raynaldlao Jul 8, 2026
35eb606
Update comments UI : Adds dark‑theme styling for SunEditor dialogs, h…
raynaldlao Jul 9, 2026
7be28be
Update comments UI : Flattens depth‑3 indentation and restructures th…
raynaldlao Jul 9, 2026
8ec17c5
Update comments UI : Reduces SunEditor line‑height to 1.4 for more co…
raynaldlao Jul 9, 2026
f683ec0
Update comments UI : Adds a honeypot anti‑spam field to comment and r…
raynaldlao Jul 9, 2026
d9b0e5c
Update comments UI : Adds honeypot anti‑spam and a 60 s per‑user rate…
raynaldlao Jul 9, 2026
58ee176
Update comments UI : Adds two‑click delete (soft → hard) with recursi…
raynaldlao Jul 10, 2026
9f1b77d
Update comments UI : Adds a YouTube‑style “view replies” toggle. Repl…
raynaldlao Jul 10, 2026
99c29e4
Update comments UI : Adds a top margin to the comments section for cl…
raynaldlao Jul 11, 2026
0f928c0
Update comments UI : Adds a dynamic “Comments (N)” count. The adapter…
raynaldlao Jul 11, 2026
9226f88
Update comments UI : Complete blocking of image insertion in the SunE…
raynaldlao Jul 11, 2026
6fd3772
Update comments UI : Adds inline JSON server‑side rendering for faste…
raynaldlao Jul 11, 2026
17b727c
Update comments UI : Adds a 5000‑character limit for comments across …
raynaldlao Jul 11, 2026
a71e0cc
Update comments UI : Adds a 5000‑character limit display in SunEditor…
raynaldlao Jul 11, 2026
51a3a04
Update comments UI : Adds a permanent label and character‑limit hint …
raynaldlao Jul 11, 2026
42613d2
Update comments UI : Removes the inset box‑shadow from buttons inside…
raynaldlao Jul 11, 2026
074f4ae
Update comments UI : Adds toast feedback and strict empty‑comment val…
raynaldlao Jul 12, 2026
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
8 changes: 6 additions & 2 deletions flask_setup/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def add_headers(self, response: Response) -> Response:
"font-src 'self' https://fonts.gstatic.com;"
"img-src 'self' data: https:;"
"frame-src https://www.youtube.com;"
"connect-src 'self' https://cdn.jsdelivr.net;"
"base-uri 'self';"
"form-action 'self';"
"report-uri /csp-report;"
Expand Down Expand Up @@ -145,8 +146,11 @@ def _add_cache_headers(response: Response) -> Response:
"""
if flask_request:
path = flask_request.path
if path.startswith(("/static/",)):
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
if path.startswith("/static/"):
if path.startswith("/static/dist/"):
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
else:
response.headers["Cache-Control"] = "no-cache"
return response


Expand Down
10 changes: 10 additions & 0 deletions frontend/core/components/ArticleViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ function BlockNoteViewer({ initialContent }) {
document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light',
);

useEffect(() => {
const el = document.querySelector('.article-static-content');
if (el) el.remove();
}, []);

useEffect(() => {
const section = document.getElementById('comments-section');
if (section) section.classList.remove('comments-hidden');
}, []);

useEffect(() => {
const el = document.documentElement;
const observer = new MutationObserver(() => {
Expand Down
11 changes: 9 additions & 2 deletions frontend/core/hooks/useArticle.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { useState, useEffect } from 'react';

export default function useArticle(articleId) {
const [loaded, setLoaded] = useState(!articleId);
const [contentStr, setContentStr] = useState('');
const ssrEl = typeof document !== 'undefined'
? document.getElementById('article-data') : null;
const ssrContent = ssrEl ? ssrEl.textContent : null;

const [loaded, setLoaded] = useState(!articleId || !!ssrContent);
const [contentStr, setContentStr] = useState(ssrContent || '');
const [title, setTitle] = useState('');
const [error, setError] = useState('');

Expand All @@ -11,6 +15,9 @@ export default function useArticle(articleId) {
setLoaded(true);
return;
}
if (ssrContent) {
return;
}
(async () => {
try {
const r = await fetch(`/api/articles/${articleId}`);
Expand Down
Loading
Loading