refactor: convert to bun workspaces monorepo

- Move web app into apps/web/
- Create packages/shared/ with shared types
- Create plugins/decky-vault/ scaffold
- Root package.json manages workspaces only
This commit is contained in:
2026-06-28 05:20:28 +08:00
parent c4bede20d4
commit cd72b7a948
345 changed files with 488 additions and 126 deletions
+52
View File
@@ -0,0 +1,52 @@
"use client"
import React from "react"
interface TiptapNode {
type: string
content?: TiptapNode[]
text?: string
marks?: { type: string; attrs?: Record<string, string> }[]
attrs?: Record<string, string>
}
export function TiptapRenderer({ content }: { content: string }) {
let parsed: TiptapNode
try {
parsed = JSON.parse(content)
} catch {
// If it's just plain text, wrap it in a paragraph
return <p className="text-sm text-text/70 whitespace-pre-line leading-relaxed">{content}</p>
}
return <div className="text-sm text-text/70 leading-relaxed">{renderNode(parsed)}</div>
}
function renderNode(node: TiptapNode, key?: number): React.ReactNode {
switch (node.type) {
case "doc":
return node.content?.map((child, i) => renderNode(child, i))
case "paragraph":
return <p key={key} className="mb-2 last:mb-0">{node.content ? node.content.map((child, i) => renderNode(child, i)) : <br />}</p>
case "text": {
let el: React.ReactNode = node.text ?? ""
node.marks?.forEach((mark) => {
if (mark.type === "bold") el = <strong key={`${key}-bold`}>{el}</strong>
if (mark.type === "italic") el = <em key={`${key}-italic`}>{el}</em>
})
return <span key={key}>{el}</span>
}
case "bulletList":
return <ul key={key} className="list-disc pl-4 mb-2">{node.content?.map((child, i) => renderNode(child, i))}</ul>
case "orderedList":
return <ol key={key} className="list-decimal pl-4 mb-2">{node.content?.map((child, i) => renderNode(child, i))}</ol>
case "listItem":
return <li key={key}>{node.content?.map((child, i) => renderNode(child, i))}</li>
case "link":
return <a key={key} href={node.attrs?.href} target="_blank" rel="noopener noreferrer" className="text-primary underline">{node.content?.map((child, i) => renderNode(child, i))}</a>
case "hardBreak":
return <br key={key} />
default:
return node.content?.map((child, i) => renderNode(child, i))
}
}