- Deleted redundant components (`AddActionButton`, `AlertBox`, `AlertStack`, `BackButton`, `CancelButton`, and `CollapsableArea`) and related files. - Removed unused models (`Book`, `BookSerie`, `BookTables`, `Character`, and `Chapter`) to reduce codebase clutter. - Updated project structure and references to reflect these removals.
141 lines
4.5 KiB
TypeScript
141 lines
4.5 KiB
TypeScript
import {TiptapAttrValue, TiptapLinkAttrs, TiptapNode} from "@/lib/types/chapter";
|
|
|
|
function isTiptapLinkAttrs(value: TiptapAttrValue): value is TiptapLinkAttrs {
|
|
return typeof value === 'object' && value !== null && 'href' in value;
|
|
}
|
|
|
|
export function getPageCount(text: string): number {
|
|
const charactersPerLine: number = 90;
|
|
const linesPerPage: number = 40;
|
|
|
|
const lines: string[] = text.split('\n');
|
|
let totalLines: number = 0;
|
|
|
|
lines.forEach((line: string) => {
|
|
const lineLength: number = line.length;
|
|
const estimatedLines: number = Math.ceil(lineLength / charactersPerLine);
|
|
totalLines += estimatedLines;
|
|
});
|
|
|
|
return Math.ceil(totalLines / linesPerPage);
|
|
}
|
|
|
|
export function convertTiptapToHTML(node: TiptapNode): string {
|
|
let html: string = '';
|
|
|
|
switch (node.type) {
|
|
case 'doc':
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
break;
|
|
|
|
case 'paragraph':
|
|
html += '<p>';
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += '</p>';
|
|
break;
|
|
|
|
case 'text':
|
|
let textContent: string = node.text || '';
|
|
|
|
if (node.attrs) {
|
|
if (node.attrs.bold) {
|
|
textContent = `<strong>${textContent}</strong>`;
|
|
}
|
|
if (node.attrs.italic) {
|
|
textContent = `<em>${textContent}</em>`;
|
|
}
|
|
if (node.attrs.underline) {
|
|
textContent = `<u>${textContent}</u>`;
|
|
}
|
|
if (node.attrs.strike) {
|
|
textContent = `<s>${textContent}</s>`;
|
|
}
|
|
if (node.attrs.link && isTiptapLinkAttrs(node.attrs.link)) {
|
|
textContent = `<a href="${node.attrs.link.href}">${textContent}</a>`;
|
|
}
|
|
}
|
|
|
|
html += textContent;
|
|
break;
|
|
|
|
case 'heading':
|
|
const level: number = typeof node.attrs?.level === 'number' ? node.attrs.level : 1;
|
|
html += `<h${level}>`;
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += `</h${level}>`;
|
|
break;
|
|
|
|
case 'bulletList':
|
|
html += '<ul>';
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += '</ul>';
|
|
break;
|
|
|
|
case 'orderedList':
|
|
html += '<ol>';
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += '</ol>';
|
|
break;
|
|
|
|
case 'listItem':
|
|
html += '<li>';
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += '</li>';
|
|
break;
|
|
|
|
case 'blockquote':
|
|
html += '<blockquote>';
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += '</blockquote>';
|
|
break;
|
|
|
|
case 'codeBlock':
|
|
html += '<pre><code>';
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
html += '</code></pre>';
|
|
break;
|
|
|
|
default:
|
|
if (node.content) {
|
|
node.content.forEach((childNode: TiptapNode) => {
|
|
html += convertTiptapToHTML(childNode);
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
|
|
return html;
|
|
}
|