feat(workspace): borderless code blocks, round code/audio/dictation blocks
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m15s

Code blocks lose border and header bar: language at the top left, a round
copy button at the bottom right on hover; converting back to text moves to
the bullet's action bubble (also for numbered items). Code, audio and
dictation blocks use fixed round corners whatever radius the theme sets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-30 22:21:17 +01:00
1 parent e243e328c7
commit 546bcba666
7 files changed
+57 -83

No files matched your search

@@ -1,6 +1,6 @@
import React, { useState, useEffect, useLayoutEffect, useMemo, useRef, useCallback } from 'react';
import Prism from 'prismjs';
import { Code, Copy, Check } from 'lucide-react';
import { Copy, Check } from 'lucide-react';
import { DocumentBlock } from '../../lib/types';
Prism.manual = true;
@@ -311,6 +311,7 @@ export interface CodeBlockEditorProps {
registerTextareaRef?: (blockId: string, el: HTMLTextAreaElement | null) => void;
onChangeContent?: (content: string) => void;
onChangeLang?: (lang: string) => void;
/** Kept for callers; converting back to text lives in the bullet's action bubble now */
onConvertToText?: () => void;
handleFocus?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
handleBlur?: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
@@ -326,7 +327,6 @@ export const CodeBlockEditor: React.FC<CodeBlockEditorProps> = ({
registerTextareaRef,
onChangeContent,
onChangeLang,
onConvertToText,
handleFocus,
handleBlur,
handleContentChange,
@@ -542,73 +542,50 @@ export const CodeBlockEditor: React.FC<CodeBlockEditorProps> = ({
const hasCustomUnknownLang = Boolean(selectValue && !KNOWN_OPTION_IDS.has(selectValue));
return (
<div className="bg-code border border-border rounded-btn my-0.5 max-w-full overflow-hidden">
{/* Code Block Header */}
<div className="flex items-center justify-between gap-2 px-2 py-1 border-b border-border text-[11px] font-mono text-faint">
<div className="flex items-center gap-1.5 min-w-0">
<Code className="w-3.5 h-3.5 text-muted shrink-0" />
{canEdit ? (
<select
aria-label="Sprache auswählen"
value={selectValue}
onChange={(e) => onChangeLang?.(e.target.value)}
className="min-h-[44px] sm:min-h-0 bg-transparent text-muted hover:text-main focus:text-main font-mono text-[11px] font-medium border border-transparent hover:border-border focus:border-accent rounded-btn px-1.5 py-0.5 outline-none cursor-pointer"
>
<option value="" className="bg-panel text-main">
Text
</option>
{hasCustomUnknownLang && (
<option value={selectValue} className="bg-panel text-main">
{selectValue}
</option>
)}
{CODE_LANGUAGE_GROUPS.map((group) => (
<optgroup key={group.label} label={group.label} className="bg-panel text-muted">
{group.options.map((opt) => (
<option key={opt.id} value={opt.id} className="bg-panel text-main">
{opt.label}
</option>
))}
</optgroup>
))}
</select>
) : (
<span className="font-mono text-[11px] text-muted px-1">{block.lang || 'Text'}</span>
)}
</div>
<div className="flex items-center gap-1.5 shrink-0">
<button
type="button"
onClick={handleCopy}
className="min-h-[44px] sm:min-h-0 px-2 py-0.5 rounded-btn text-[11px] font-mono text-muted hover:text-main hover:bg-panel-elevated transition-colors inline-flex items-center gap-1 cursor-pointer"
title="In die Zwischenablage kopieren"
<div className="group/code relative bg-code rounded-2xl my-0.5 max-w-full overflow-hidden">
{/* Language at the top left; no header bar */}
<div className="flex items-center px-1.5 pt-1 text-[11px] font-mono text-faint">
{canEdit ? (
<select
aria-label="Sprache auswählen"
value={selectValue}
onChange={(e) => onChangeLang?.(e.target.value)}
className="min-h-[44px] sm:min-h-0 bg-transparent text-faint hover:text-main focus:text-main font-mono text-[11px] font-medium border border-transparent hover:border-border focus:border-accent rounded-btn px-1 py-0.5 outline-none cursor-pointer"
>
{copied ? (
<>
<Check className="w-3 h-3 text-status-ok" />
<span className="text-status-ok">Kopiert!</span>
</>
) : (
<>
<Copy className="w-3 h-3 opacity-75" />
<span>Kopieren</span>
</>
<option value="" className="bg-panel text-main">
Text
</option>
{hasCustomUnknownLang && (
<option value={selectValue} className="bg-panel text-main">
{selectValue}
</option>
)}
</button>
{canEdit && onConvertToText && (
<button
type="button"
onClick={onConvertToText}
className="min-h-[44px] sm:min-h-0 px-2 py-0.5 rounded-btn text-[11px] font-mono text-muted hover:text-accent hover:bg-panel-elevated transition-colors inline-flex items-center cursor-pointer"
>
Als Text
</button>
)}
</div>
{CODE_LANGUAGE_GROUPS.map((group) => (
<optgroup key={group.label} label={group.label} className="bg-panel text-muted">
{group.options.map((opt) => (
<option key={opt.id} value={opt.id} className="bg-panel text-main">
{opt.label}
</option>
))}
</optgroup>
))}
</select>
) : (
<span className="font-mono text-[11px] text-faint px-1">{block.lang || 'Text'}</span>
)}
</div>
{/* Copy: round icon button at the bottom right, shown on hover (always on touch screens) */}
<button
type="button"
onClick={handleCopy}
className="absolute bottom-2 right-2 z-10 h-9 w-9 sm:h-8 sm:w-8 rounded-full bg-panel border border-border shadow-panel flex items-center justify-center text-muted hover:text-main opacity-100 sm:opacity-0 sm:group-hover/code:opacity-100 focus-visible:opacity-100 transition-opacity cursor-pointer"
title={copied ? 'Kopiert!' : 'In die Zwischenablage kopieren'}
aria-label={copied ? 'Kopiert!' : 'Kopieren'}
>
{copied ? <Check className="w-3.5 h-3.5 text-status-ok" /> : <Copy className="w-3.5 h-3.5" />}
</button>
{/* Live Highlighted Overlay + Textarea with Line Numbers */}
<div className="flex relative w-full overflow-hidden">
{/* Line Numbers Column */}
@@ -618,7 +595,7 @@ export const CodeBlockEditor: React.FC<CodeBlockEditorProps> = ({
onScroll={handleLineNumbersScroll}
onWheel={handleLineNumbersWheel}
data-testid="code-line-numbers"
className="select-none py-2 pl-2.5 pr-2 font-mono text-xs text-faint leading-relaxed text-right border-r border-border/40 shrink-0 overflow-hidden"
className="select-none py-2 pl-2.5 pr-2 font-mono text-xs text-faint leading-relaxed text-right shrink-0 overflow-hidden"
>
{Array.from({ length: lineCount }, (_, i) => (
<div key={i + 1} data-line-number={i + 1}>