feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
import type { NodeComponentProps } from 'markstream-react';
|
||||
interface ThinkingNodeData {
|
||||
node: {
|
||||
type: 'thinking';
|
||||
content: string;
|
||||
loading?: boolean;
|
||||
attrs?: Array<{
|
||||
name: string;
|
||||
value: string | boolean;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
export declare function ThinkingNode(props: NodeComponentProps<ThinkingNodeData['node']>): import("react/jsx-runtime").JSX.Element;
|
||||
export default ThinkingNode;
|
||||
//# sourceMappingURL=ThinkingNode.d.ts.map
|
||||
@@ -0,0 +1,100 @@
|
||||
import type { NodeComponentProps } from 'markstream-react'
|
||||
import type { ReactNode } from 'react'
|
||||
import { NodeRenderer } from 'markstream-react'
|
||||
import { PLAYGROUND_CUSTOM_HTML_TAGS } from '../../../playground-react18/src/shared/markstreamPlayground'
|
||||
|
||||
interface ThinkingNodeData {
|
||||
node: {
|
||||
type: 'thinking'
|
||||
content: string
|
||||
loading?: boolean
|
||||
attrs?: Array<{ name: string, value: string | boolean }>
|
||||
}
|
||||
}
|
||||
|
||||
type ThinkingNodeProps = Partial<NodeComponentProps<ThinkingNodeData['node']>> & {
|
||||
children?: ReactNode
|
||||
}
|
||||
|
||||
function getResolvedNode(props: ThinkingNodeProps): ThinkingNodeData['node'] {
|
||||
if (props.node)
|
||||
return props.node
|
||||
|
||||
return {
|
||||
type: 'thinking',
|
||||
content: '',
|
||||
loading: false,
|
||||
}
|
||||
}
|
||||
|
||||
export function ThinkingNode(props: ThinkingNodeProps) {
|
||||
const node = getResolvedNode(props)
|
||||
const dotsClass = node.loading ? 'thinking-dots visible' : 'thinking-dots hidden'
|
||||
const ctx = props.ctx
|
||||
const inheritedCustomId = props.customId ?? ctx?.customId
|
||||
const inheritedIsDark = props.isDark ?? ctx?.isDark
|
||||
const inheritedTypewriter = props.typewriter ?? ctx?.typewriter ?? true
|
||||
const hasStructuredNode = Boolean(props.node)
|
||||
|
||||
return (
|
||||
<div className="thinking-node p-4 my-4 bg-blue-50 dark:bg-blue-900/40 rounded-md border-l-4 border-blue-400 flex items-start gap-3">
|
||||
<div className="flex-shrink-0 mt-1">
|
||||
<div className="w-9 h-9 rounded-full bg-blue-200 dark:bg-blue-700 flex items-center justify-center text-blue-700 dark:text-blue-100">
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path
|
||||
d="M12 3C7.03 3 3 6.58 3 11c0 1.86.66 3.57 1.77 4.98L4 21l5.2-1.9C10.06 19.35 11 19.5 12 19.5c4.97 0 9-3.58 9-8.5S16.97 3 12 3z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="0.8"
|
||||
fill="currentColor"
|
||||
opacity="0.9"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-baseline gap-3">
|
||||
<strong className="text-sm">Thinking</strong>
|
||||
<span className="text-xs text-slate-500 dark:text-slate-300">(assistant)</span>
|
||||
<span className="ml-2" aria-hidden="true">
|
||||
<span className={dotsClass} aria-hidden="true">
|
||||
<span className="dot dot-1" />
|
||||
<span className="dot dot-2" />
|
||||
<span className="dot dot-3" />
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 text-sm leading-relaxed text-slate-800 dark:text-slate-100">
|
||||
{node.loading && <span className="sr-only" aria-live="polite">Thinking…</span>}
|
||||
<div className="content-area">
|
||||
{hasStructuredNode
|
||||
? (
|
||||
<NodeRenderer
|
||||
content={String(node.content ?? '')}
|
||||
customId={inheritedCustomId}
|
||||
customHtmlTags={PLAYGROUND_CUSTOM_HTML_TAGS}
|
||||
isDark={inheritedIsDark}
|
||||
themes={ctx?.codeBlockThemes?.themes}
|
||||
codeBlockDarkTheme={ctx?.codeBlockThemes?.darkTheme}
|
||||
codeBlockLightTheme={ctx?.codeBlockThemes?.lightTheme}
|
||||
codeBlockMonacoOptions={ctx?.codeBlockThemes?.monacoOptions}
|
||||
codeBlockMinWidth={ctx?.codeBlockThemes?.minWidth}
|
||||
codeBlockMaxWidth={ctx?.codeBlockThemes?.maxWidth}
|
||||
codeBlockProps={ctx?.codeBlockProps}
|
||||
codeBlockStream={ctx?.codeBlockStream}
|
||||
renderCodeBlocksAsPre={ctx?.renderCodeBlocksAsPre}
|
||||
typewriter={inheritedTypewriter}
|
||||
viewportPriority={false}
|
||||
deferNodesUntilVisible={false}
|
||||
batchRendering={false}
|
||||
maxLiveNodes={0}
|
||||
/>
|
||||
)
|
||||
: props.children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThinkingNode
|
||||
Reference in New Issue
Block a user