Merge pull request '[FA-misc] Should fix paragraph blocking' (#46) from hotfix/FA-misc_FixParagraphBlocking into master
All checks were successful
CI / build-backend (push) Successful in 1m2s
CI / build-frontend (push) Successful in 37s
Build Gateway / build-subgraphs (map[name:novel-service project:FictionArchive.Service.NovelService subgraph:Novel]) (push) Successful in 46s
Build Gateway / build-subgraphs (map[name:scheduler-service project:FictionArchive.Service.SchedulerService subgraph:Scheduler]) (push) Successful in 41s
Build Gateway / build-subgraphs (map[name:translation-service project:FictionArchive.Service.TranslationService subgraph:Translation]) (push) Successful in 46s
Build Gateway / build-subgraphs (map[name:user-service project:FictionArchive.Service.UserService subgraph:User]) (push) Successful in 42s
Release / build-and-push (map[dockerfile:FictionArchive.Service.AuthenticationService/Dockerfile name:authentication-service]) (push) Successful in 2m7s
Release / build-and-push (map[dockerfile:FictionArchive.Service.FileService/Dockerfile name:file-service]) (push) Successful in 1m52s
Release / build-and-push (map[dockerfile:FictionArchive.Service.NovelService/Dockerfile name:novel-service]) (push) Successful in 1m49s
Release / build-and-push (map[dockerfile:FictionArchive.Service.SchedulerService/Dockerfile name:scheduler-service]) (push) Successful in 1m50s
Release / build-and-push (map[dockerfile:FictionArchive.Service.TranslationService/Dockerfile name:translation-service]) (push) Successful in 1m57s
Release / build-and-push (map[dockerfile:FictionArchive.Service.UserService/Dockerfile name:user-service]) (push) Successful in 1m42s
Release / build-frontend (push) Successful in 1m48s
Build Gateway / build-gateway (push) Successful in 3m39s
All checks were successful
CI / build-backend (push) Successful in 1m2s
CI / build-frontend (push) Successful in 37s
Build Gateway / build-subgraphs (map[name:novel-service project:FictionArchive.Service.NovelService subgraph:Novel]) (push) Successful in 46s
Build Gateway / build-subgraphs (map[name:scheduler-service project:FictionArchive.Service.SchedulerService subgraph:Scheduler]) (push) Successful in 41s
Build Gateway / build-subgraphs (map[name:translation-service project:FictionArchive.Service.TranslationService subgraph:Translation]) (push) Successful in 46s
Build Gateway / build-subgraphs (map[name:user-service project:FictionArchive.Service.UserService subgraph:User]) (push) Successful in 42s
Release / build-and-push (map[dockerfile:FictionArchive.Service.AuthenticationService/Dockerfile name:authentication-service]) (push) Successful in 2m7s
Release / build-and-push (map[dockerfile:FictionArchive.Service.FileService/Dockerfile name:file-service]) (push) Successful in 1m52s
Release / build-and-push (map[dockerfile:FictionArchive.Service.NovelService/Dockerfile name:novel-service]) (push) Successful in 1m49s
Release / build-and-push (map[dockerfile:FictionArchive.Service.SchedulerService/Dockerfile name:scheduler-service]) (push) Successful in 1m50s
Release / build-and-push (map[dockerfile:FictionArchive.Service.TranslationService/Dockerfile name:translation-service]) (push) Successful in 1m57s
Release / build-and-push (map[dockerfile:FictionArchive.Service.UserService/Dockerfile name:user-service]) (push) Successful in 1m42s
Release / build-frontend (push) Successful in 1m48s
Build Gateway / build-gateway (push) Successful in 3m39s
Reviewed-on: #46
This commit was merged in pull request #46.
This commit is contained in:
@@ -155,10 +155,9 @@
|
|||||||
<Card>
|
<Card>
|
||||||
<CardContent class="px-6 py-8 md:px-12">
|
<CardContent class="px-6 py-8 md:px-12">
|
||||||
<article
|
<article
|
||||||
class="prose prose-lg dark:prose-invert mx-auto max-w-none whitespace-pre-line
|
class="prose prose-lg dark:prose-invert mx-auto max-w-none
|
||||||
prose-p:text-foreground prose-p:mb-4 prose-p:leading-relaxed
|
|
||||||
prose-headings:text-foreground
|
prose-headings:text-foreground
|
||||||
first:prose-p:mt-0 last:prose-p:mb-0"
|
[&>p]:text-foreground [&>p]:mb-6 [&>p]:leading-relaxed"
|
||||||
>
|
>
|
||||||
{@html sanitizedBody}
|
{@html sanitizedBody}
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -1,12 +1,42 @@
|
|||||||
import DOMPurify from 'isomorphic-dompurify';
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits plain text into paragraphs based on newlines.
|
||||||
|
* Double newlines create new paragraphs, single newlines become <br>.
|
||||||
|
* If the content already contains HTML block elements, returns as-is.
|
||||||
|
*/
|
||||||
|
function wrapInParagraphs(text: string): string {
|
||||||
|
// Check if content already has block-level HTML elements
|
||||||
|
const hasBlockElements = /<(p|div|h[1-6]|ul|ol|blockquote|pre|table|hr)[>\s]/i.test(text);
|
||||||
|
if (hasBlockElements) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split on double newlines (paragraph breaks)
|
||||||
|
const paragraphs = text.split(/\n\s*\n/);
|
||||||
|
|
||||||
|
return paragraphs
|
||||||
|
.map((para) => {
|
||||||
|
const trimmed = para.trim();
|
||||||
|
if (!trimmed) return '';
|
||||||
|
// Convert single newlines to <br> within paragraphs
|
||||||
|
const withBreaks = trimmed.replace(/\n/g, '<br>');
|
||||||
|
return `<p>${withBreaks}</p>`;
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sanitizes chapter HTML content with extended allowed tags.
|
* Sanitizes chapter HTML content with extended allowed tags.
|
||||||
* More permissive than the description sanitizer to support
|
* More permissive than the description sanitizer to support
|
||||||
* formatted novel content including headings, lists, and images.
|
* formatted novel content including headings, lists, and images.
|
||||||
|
* Also wraps plain text in paragraph tags for better browser translate support.
|
||||||
*/
|
*/
|
||||||
export function sanitizeChapterHtml(html: string): string {
|
export function sanitizeChapterHtml(html: string): string {
|
||||||
return DOMPurify.sanitize(html, {
|
// First wrap in paragraphs if needed, then sanitize
|
||||||
|
const wrapped = wrapInParagraphs(html);
|
||||||
|
return DOMPurify.sanitize(wrapped, {
|
||||||
ALLOWED_TAGS: [
|
ALLOWED_TAGS: [
|
||||||
// Basic formatting
|
// Basic formatting
|
||||||
'b',
|
'b',
|
||||||
|
|||||||
Reference in New Issue
Block a user