The editor was overflowing its container because @uiw/react-codemirror
renders a wrapper div that doesn't inherit flex constraints by default.
Fixed by adding CSS rules that:
1. Set overflow:hidden on .cm-editor-container
2. Target the wrapper div (> div) with flex:1, min-height:0, overflow:hidden
3. Set .cm-editor and .cm-scroller to overflow appropriately
This ensures the flex height constraint propagates through every level
of the CodeMirror DOM tree, and only .cm-scroller scrolls.
Layout chain:
.cm-editor-container (flex-1, min-h-0)
└─ wrapper div (flex:1, min-h-0, overflow:hidden)
└─ .cm-editor (flex:1, min-h-0, overflow:hidden)
└─ .cm-scroller (min-h-0, overflow:auto) ← only this scrolls
324 lines
6.0 KiB
CSS
324 lines
6.0 KiB
CSS
@import "tailwindcss";
|
|
|
|
@theme {
|
|
--color-brand: #c20600;
|
|
--color-bg-primary: #0a0a0a;
|
|
--color-bg-secondary: #121212;
|
|
--color-bg-tertiary: #1a1a1a;
|
|
--color-bg-elevated: #202020;
|
|
--color-text-primary: #d4d4d4;
|
|
--color-text-secondary: #a3a3a3;
|
|
--color-text-muted: #737373;
|
|
--color-border-subtle: #1a1a1a;
|
|
--color-border-default: #2a2a2a;
|
|
--color-border-highlight: #3a3a3a;
|
|
|
|
--font-mono: "Fira Code", "Courier New", Courier, monospace;
|
|
--font-sans:
|
|
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
|
|
--spacing-header: 48px;
|
|
--spacing-status: 32px;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-family: var(--font-sans);
|
|
background-color: var(--color-bg-primary);
|
|
color: var(--color-text-primary);
|
|
line-height: 1.5;
|
|
font-size: 14px;
|
|
}
|
|
|
|
#root {
|
|
height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
a {
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover {
|
|
text-decoration: none;
|
|
}
|
|
|
|
button {
|
|
cursor: pointer;
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
}
|
|
|
|
.tool-call {
|
|
margin-top: theme("spacing.4");
|
|
margin-bottom: theme("spacing.4");
|
|
}
|
|
|
|
.tool-call + .tool-call {
|
|
margin-top: 0;
|
|
}
|
|
|
|
input,
|
|
textarea {
|
|
font-family: inherit;
|
|
font-size: inherit;
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
::-webkit-scrollbar-track {
|
|
background: var(--color-bg-secondary);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--color-border-default);
|
|
}
|
|
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--color-border-highlight);
|
|
}
|
|
|
|
@keyframes strobe {
|
|
0%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.4;
|
|
}
|
|
}
|
|
|
|
.strobe {
|
|
animation: strobe 1.2s ease-in-out infinite;
|
|
}
|
|
|
|
/* ── CodeMirror Editor Layout ─────────────────────────────── */
|
|
/* The CodeMirror component must be constrained to its flex allocation
|
|
* and scroll within it. The layout chain is:
|
|
*
|
|
* .cm-editor-container (flex-1, min-h-0 in the flex column)
|
|
* └─ <div> (wrapper div rendered by @uiw/react-codemirror)
|
|
* └─ .cm-editor (the actual editor chrome)
|
|
* └─ .cm-scroller (the scrollable content area)
|
|
*
|
|
* Every level must have height:100% and overflow:hidden so the
|
|
* scroller is the only thing that scrolls.
|
|
*/
|
|
.cm-editor-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* The wrapper div that @uiw/react-codemirror renders directly inside
|
|
* the container — this is NOT .cm-editor, it's the parent of .cm-editor.
|
|
* Must fill the container and pass the height constraint down. */
|
|
.cm-editor-container > div {
|
|
flex: 1;
|
|
min-height: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.cm-editor-container .cm-editor {
|
|
flex: 1;
|
|
min-height: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.cm-editor-container .cm-scroller {
|
|
min-height: 0;
|
|
overflow: auto;
|
|
}
|
|
|
|
/* ── Gadget Markdown Styles ─────────────────────────────────── */
|
|
/* Dense, technical display — no blog-style whitespace */
|
|
|
|
.gadget-markdown {
|
|
color: var(--color-text-primary);
|
|
line-height: 1.5;
|
|
word-break: break-word;
|
|
display: inline-block;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
margin-bottom: 8px;
|
|
|
|
:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.gadget-markdown h1,
|
|
.gadget-markdown h2,
|
|
.gadget-markdown h3,
|
|
.gadget-markdown h4,
|
|
.gadget-markdown h5,
|
|
.gadget-markdown h6 {
|
|
color: #e8e8e8;
|
|
font-weight: 600;
|
|
line-height: 1.25;
|
|
margin-top: 0.5rem;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.gadget-markdown h1 {
|
|
font-size: 1.5em;
|
|
/* border-bottom: 1px solid var(--color-border-default); */
|
|
padding-bottom: 0.2em;
|
|
}
|
|
.gadget-markdown h2 {
|
|
font-size: 1.4em;
|
|
/* border-bottom: 1px solid var(--color-border-default); */
|
|
padding-bottom: 0.15em;
|
|
}
|
|
.gadget-markdown h3 {
|
|
font-size: 1.3em;
|
|
}
|
|
.gadget-markdown h4 {
|
|
font-size: 1.2em;
|
|
}
|
|
.gadget-markdown h5 {
|
|
font-size: 1.1em;
|
|
}
|
|
.gadget-markdown h6 {
|
|
font-size: 1em;
|
|
}
|
|
|
|
.gadget-markdown p {
|
|
margin-top: 0;
|
|
margin-bottom: 0.8rem;
|
|
}
|
|
|
|
.gadget-markdown a {
|
|
color: #60a5fa;
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.gadget-markdown a:hover {
|
|
color: #93c5fd;
|
|
}
|
|
|
|
/* Inline code */
|
|
.gadget-markdown code:not(pre code) {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.85em;
|
|
background: #1e1e1e;
|
|
color: rgb(219, 219, 7);
|
|
padding: 0.1em 0.3em;
|
|
border-radius: 3px;
|
|
border: 1px solid #2d2d2d;
|
|
}
|
|
|
|
/* Code blocks */
|
|
.gadget-markdown pre {
|
|
line-height: 1rem;
|
|
background: #0d0d0d;
|
|
border: 1px solid #2a2a2a;
|
|
border-radius: 4px;
|
|
padding: 0.5rem 0.7rem;
|
|
overflow-x: auto;
|
|
margin-bottom: 0.5rem;
|
|
max-width: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
.gadget-markdown pre code {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.85em;
|
|
color: #d4d4d4;
|
|
background: transparent;
|
|
padding: 0;
|
|
border: none;
|
|
border-radius: 0;
|
|
}
|
|
|
|
/* Tables */
|
|
.gadget-markdown table {
|
|
width: auto;
|
|
max-width: 100%;
|
|
border-collapse: collapse;
|
|
margin-bottom: 0.5rem;
|
|
font-size: 0.85em;
|
|
}
|
|
|
|
.gadget-markdown th,
|
|
.gadget-markdown td {
|
|
border: 1px solid #2a2a2a;
|
|
padding: 0.35em 0.6em;
|
|
text-align: left;
|
|
}
|
|
|
|
.gadget-markdown th {
|
|
background: #1a1a1a;
|
|
color: #e8e8e8;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.gadget-markdown tr:nth-child(even) td {
|
|
background: #111111;
|
|
}
|
|
|
|
.gadget-markdown tr:nth-child(odd) td {
|
|
background: #0d0d0d;
|
|
}
|
|
|
|
/* Blockquotes */
|
|
.gadget-markdown blockquote {
|
|
border-left: 2px solid #3a3a3a;
|
|
margin: 0 0 0.35rem 0;
|
|
padding: 0.25rem 0.6rem;
|
|
color: var(--color-text-muted);
|
|
background: #111111;
|
|
border-radius: 0 3px 3px 0;
|
|
}
|
|
|
|
/* Lists */
|
|
.gadget-markdown ul,
|
|
.gadget-markdown ol {
|
|
margin-bottom: 0.35rem;
|
|
padding-left: 1.2rem;
|
|
}
|
|
|
|
.gadget-markdown li {
|
|
margin-bottom: 0.15rem;
|
|
}
|
|
|
|
.gadget-markdown li::marker {
|
|
color: var(--color-text-muted);
|
|
}
|
|
|
|
/* Horizontal rule */
|
|
.gadget-markdown hr {
|
|
border: none;
|
|
border-top: 1px solid var(--color-border-default);
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
/* Images */
|
|
.gadget-markdown img {
|
|
max-width: 100%;
|
|
border-radius: 4px;
|
|
border: 1px solid var(--color-border-default);
|
|
}
|
|
|
|
/* Strong / em */
|
|
.gadget-markdown strong {
|
|
color: #e8e8e8;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.gadget-markdown em {
|
|
color: #c4c4c4;
|
|
}
|