Skip to content
File

Blob: src/client/components/editor/styles/ai-suggestion.css

css206 lines
1.tiptap-ai-target {
2 background: color-mix(in oklab, var(--color-accent-500) 22%, transparent);
3 border-radius: 2px;
4}
5 
6.tiptap-ai-preview {
7 display: block;
8 margin: 6px 0;
9 padding: 10px 12px;
10 width: 100%;
11 max-width: 40rem;
12 border-radius: 6px;
13 background: color-mix(in oklab, var(--color-accent-500) 14%, transparent);
14 border: 1px solid color-mix(in oklab, var(--color-accent-500) 45%, transparent);
15 color: var(--color-zinc-100);
16 font-size: 0.92em;
17 white-space: normal;
18 box-sizing: border-box;
19}
20 
21.tiptap-ai-preview-streaming {
22 background: color-mix(in oklab, var(--color-accent-500) 9%, transparent);
23}
24 
25.tiptap-ai-preview-error {
26 background: color-mix(in oklab, var(--color-red-500, #ef4444) 12%, transparent);
27 border-color: color-mix(in oklab, var(--color-red-500, #ef4444) 45%, transparent);
28}
29 
30.tiptap-ai-preview-bubble {
31 display: block;
32 min-height: 1.35em;
33 word-break: break-word;
34 color: var(--color-zinc-100);
35}
36 
37.tiptap-ai-preview-actions {
38 display: flex;
39 justify-content: flex-end;
40 align-items: center;
41 gap: 8px;
42 margin-top: 8px;
43 padding-top: 8px;
44 border-top: 1px solid color-mix(in oklab, var(--color-accent-500) 22%, transparent);
45 font-size: 0.82em;
46 color: var(--color-zinc-400);
47}
48 
49.tiptap-ai-preview-divider {
50 color: color-mix(in oklab, var(--color-zinc-400) 70%, transparent);
51 user-select: none;
52}
53 
54.tiptap-ai-preview-bubble-pending {
55 color: var(--color-zinc-400);
56 font-style: italic;
57 animation: tiptap-ai-preview-pending 1.2s ease-in-out infinite;
58}
59 
60@keyframes tiptap-ai-preview-pending {
61 0%,
62 100% {
63 opacity: 0.55;
64 }
65 50% {
66 opacity: 1;
67 }
68}
69 
70.tiptap-ai-preview-action {
71 appearance: none;
72 border: none;
73 background: transparent;
74 color: inherit;
75 font: inherit;
76 cursor: pointer;
77 padding: 2px 4px;
78 display: inline-flex;
79 align-items: center;
80 gap: 6px;
81 border-radius: 4px;
82}
83 
84.tiptap-ai-preview-action:hover:not(:disabled),
85.tiptap-ai-preview-action:focus-visible {
86 color: var(--color-zinc-100);
87 outline: none;
88}
89 
90.tiptap-ai-preview-action:disabled {
91 cursor: not-allowed;
92 opacity: 0.5;
93}
94 
95/* Shared kbd pill — reused by rewrite preview actions and the /continue
96 indicator's cancel. Mono, double-bottom border for a "key" texture, accent
97 tint so it reads as part of the AI surface family. */
98.tiptap-ai-kbd {
99 font-family: var(--font-mono);
100 font-size: 0.88em;
101 font-style: normal;
102 font-weight: 500;
103 min-width: 1.8em;
104 padding: 1px 5px;
105 border: 1px solid color-mix(in oklab, var(--color-accent-500) 40%, transparent);
106 border-bottom-width: 2px;
107 background: color-mix(in oklab, var(--color-accent-500) 10%, transparent);
108 border-radius: 3px;
109 color: var(--color-zinc-200);
110 line-height: 1.2;
111 text-align: center;
112}
113 
114.tiptap-ai-preview-action:hover:not(:disabled) .tiptap-ai-kbd,
115.tiptap-ai-preview-action:focus-visible .tiptap-ai-kbd,
116.tiptap-ai-generate-cancel:hover .tiptap-ai-kbd,
117.tiptap-ai-generate-cancel:focus-visible .tiptap-ai-kbd {
118 background: color-mix(in oklab, var(--color-accent-500) 22%, transparent);
119 color: var(--color-zinc-100);
120}
121 
122.tiptap-ai-preview-accept .tiptap-ai-kbd {
123 color: var(--color-accent-300);
124 border-color: color-mix(in oklab, var(--color-accent-500) 55%, transparent);
125}
126 
127/* inline-block (not inline-flex) so Firefox's caret renderer measures against
128 the text line box, not the flex line; otherwise the native caret stretches
129 to the tallest child and the dot drifts off the x-height. */
130.tiptap-ai-generate-indicator {
131 display: inline-block;
132 vertical-align: baseline;
133 color: color-mix(in oklab, var(--color-accent-400) 75%, var(--color-zinc-400));
134 font-style: italic;
135 font-weight: 400;
136 user-select: none;
137}
138 
139/* The empty-paragraph placeholder ("Start typing, or press / …") would bleed
140 under the ghost indicator, so suppress it while the indicator is inline. */
141.tiptap > p.is-empty:has(.tiptap-ai-generate-indicator)::before {
142 display: none;
143}
144 
145/* Firefox measures the native caret against the paragraph's full line-box, so
146 inline widgets stretch it to a tall bar. The "Continuing…" indicator already
147 communicates the pending state, so hide the native caret while it's active
148 for pixel-identical rendering across browsers. */
149.tiptap > p:has(.tiptap-ai-generate-indicator) {
150 caret-color: transparent;
151}
152 
153.tiptap-ai-generate-indicator-dot {
154 display: inline-block;
155 vertical-align: middle;
156 width: 5px;
157 height: 5px;
158 border-radius: 50%;
159 margin: 0 6px 0 10px;
160 background: currentColor;
161 animation: tiptap-ai-generate-pulse 1.1s ease-in-out infinite;
162}
163 
164.tiptap-ai-generate-indicator-label {
165 margin-right: 6px;
166}
167 
168.tiptap-ai-generate-cancel {
169 appearance: none;
170 border: none;
171 background: transparent;
172 color: color-mix(in oklab, currentColor 75%, var(--color-zinc-200));
173 cursor: pointer;
174 padding: 0 2px;
175 font-family: inherit;
176 font-weight: inherit;
177 font-style: normal;
178 /* Scaled down so the kbd pill sits at the same optical size as the preview
179 footer (~0.82em × 0.88em kbd), instead of competing with the italic label
180 at body size. */
181 font-size: 0.82em;
182 display: inline-flex;
183 align-items: center;
184 gap: 5px;
185 border-radius: 4px;
186 vertical-align: baseline;
187}
188 
189.tiptap-ai-generate-cancel:hover,
190.tiptap-ai-generate-cancel:focus-visible {
191 color: var(--color-zinc-100);
192 outline: none;
193}
194 
195@keyframes tiptap-ai-generate-pulse {
196 0%,
197 100% {
198 opacity: 0.35;
199 transform: scale(0.8);
200 }
201 50% {
202 opacity: 1;
203 transform: scale(1);
204 }
205}