Jaspers Hub

jaspers / yfinance

pluginOfficialReviewed★ 0↓ 11

yfinance: Free Yahoo Finance market data (quotes, history, fundamentals, options, news, movers) via a bundled MCP server, with five views.

10 KB
1/* The Yahoo Finance views' CSS. A plugin view is an iframe of its own, so there is no Tailwind here:
2 plain classes, the house style by hand. Colours are the app's theme variables, so the views follow
3 its light and dark, each with its light value as the fallback for an app from before the theme;
4 colours of the plugin's own take their dark values at the end. Square everything, one grey line,
5 muted secondary text, 13px, figures of one width, and no accent colour but the sign of a number. */
6
7.yf-root {
8 display: flex;
9 flex-direction: column;
10 height: 100%;
11 width: 100%;
12 background: var(--jaspers-background, #fff);
13 color: var(--jaspers-foreground, #171717);
14 font: 13px/1.45 var(--jaspers-font-sans, system-ui, -apple-system, sans-serif);
15}
16
17button,
18input,
19select {
20 font: inherit;
21 border-radius: 0;
22}
23
24.yf-bar {
25 flex: 0 0 auto;
26 display: flex;
27 align-items: center;
28 flex-wrap: wrap;
29 gap: 8px;
30 padding: 6px 8px;
31 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
32}
33
34.yf-input,
35.yf-select {
36 border: 1px solid var(--jaspers-border, #e5e5e5);
37 background: var(--jaspers-background, #fff);
38 color: var(--jaspers-foreground, #171717);
39 padding: 2px 6px;
40 outline: none;
41}
42
43.yf-input:focus,
44.yf-select:focus {
45 border-color: var(--jaspers-foreground, #171717);
46}
47
48.yf-symbol {
49 width: 96px;
50 text-transform: uppercase;
51}
52
53.yf-symbol::placeholder {
54 text-transform: none;
55}
56
57.yf-label {
58 display: inline-flex;
59 align-items: center;
60 gap: 4px;
61}
62
63.yf-body {
64 flex: 1 1 auto;
65 overflow: auto;
66 padding: 0 8px 8px;
67}
68
69.yf-muted {
70 color: var(--jaspers-muted-foreground, #737373);
71}
72
73.yf-strong {
74 font-weight: 600;
75}
76
77.yf-num {
78 font-variant-numeric: tabular-nums;
79 white-space: nowrap;
80}
81
82.yf-up {
83 color: var(--jaspers-positive, #15803d);
84}
85
86.yf-down,
87.yf-negative {
88 color: var(--jaspers-negative, #b91c1c);
89}
90
91.yf-error {
92 color: var(--jaspers-destructive, #dc2626);
93 white-space: pre-wrap;
94 margin: 4px 0;
95}
96
97.yf-empty {
98 color: var(--jaspers-muted-foreground, #737373);
99 padding: 12px 0;
100 margin: 0;
101}
102
103.yf-line {
104 margin: 2px 0 6px;
105}
106
107.yf-link {
108 border: 0;
109 background: none;
110 color: inherit;
111 padding: 0;
112 cursor: pointer;
113 text-align: left;
114}
115
116.yf-link:hover {
117 text-decoration: underline;
118}
119
120/* Sections. */
121
122.yf-section {
123 padding-top: 10px;
124}
125
126.yf-section + .yf-section {
127 margin-top: 4px;
128 border-top: 1px solid var(--jaspers-border, #e5e5e5);
129}
130
131.yf-h {
132 display: flex;
133 align-items: baseline;
134 flex-wrap: wrap;
135 gap: 4px 10px;
136 margin: 0 0 6px;
137 font-size: 13px;
138 font-weight: 600;
139}
140
141.yf-aside {
142 font-weight: 400;
143}
144
145/* Tabs and toggles. */
146
147.yf-tabs,
148.yf-toggle {
149 display: inline-flex;
150}
151
152.yf-tab {
153 border: 1px solid var(--jaspers-border, #e5e5e5);
154 background: var(--jaspers-background, #fff);
155 color: var(--jaspers-foreground, #404040);
156 padding: 2px 8px;
157 cursor: pointer;
158}
159
160.yf-tab + .yf-tab {
161 border-left: 0;
162}
163
164.yf-tab:hover:not(:disabled) {
165 background: var(--jaspers-muted, #f5f5f5);
166}
167
168.yf-tab:disabled {
169 color: #d4d4d4;
170 cursor: default;
171}
172
173.yf-tab-on,
174.yf-tab-on:hover:not(:disabled) {
175 background: var(--jaspers-primary, #171717);
176 border-color: var(--jaspers-primary, #171717);
177 color: var(--jaspers-primary-foreground, #fff);
178}
179
180/* Tables. */
181
182.yf-table {
183 border-collapse: collapse;
184 width: 100%;
185 margin: 2px 0 6px;
186}
187
188.yf-table th,
189.yf-table td {
190 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
191 padding: 3px 6px;
192 text-align: left;
193 white-space: nowrap;
194 vertical-align: baseline;
195}
196
197.yf-table th {
198 position: sticky;
199 top: 0;
200 z-index: 1;
201 background: var(--jaspers-background, #fff);
202 font-weight: 500;
203 color: var(--jaspers-muted-foreground, #737373);
204}
205
206.yf-table th.yf-num,
207.yf-table td.yf-num {
208 text-align: right;
209}
210
211.yf-fit {
212 width: auto;
213 min-width: min(100%, 560px);
214}
215
216.yf-table tbody tr:hover td {
217 background: var(--jaspers-muted, #fafafa);
218}
219
220.yf-name-cell {
221 max-width: 260px;
222 overflow: hidden;
223 text-overflow: ellipsis;
224}
225
226.yf-x {
227 border: 0;
228 background: none;
229 color: #a3a3a3;
230 padding: 0 4px;
231 cursor: pointer;
232 font-size: 15px;
233 line-height: 1;
234}
235
236.yf-x:hover {
237 color: var(--jaspers-foreground, #171717);
238}
239
240/* Company overview. */
241
242.yf-head {
243 padding-top: 10px;
244}
245
246.yf-title {
247 display: flex;
248 align-items: baseline;
249 flex-wrap: wrap;
250 gap: 4px 10px;
251}
252
253.yf-name {
254 font-size: 16px;
255 font-weight: 600;
256}
257
258.yf-price-line {
259 display: flex;
260 align-items: baseline;
261 flex-wrap: wrap;
262 gap: 4px 10px;
263 margin: 4px 0 2px;
264}
265
266.yf-price {
267 font-size: 24px;
268 font-weight: 600;
269 letter-spacing: -0.01em;
270}
271
272.yf-ranges {
273 display: grid;
274 grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
275 gap: 4px 24px;
276 margin: 8px 0 2px;
277}
278
279.yf-range {
280 min-width: 0;
281}
282
283.yf-range-label {
284 font-size: 12px;
285 margin-bottom: 3px;
286}
287
288.yf-track {
289 position: relative;
290 height: 4px;
291 background: var(--jaspers-border, #e5e5e5);
292 margin: 5px 0;
293}
294
295.yf-mark {
296 position: absolute;
297 top: -4px;
298 width: 2px;
299 height: 12px;
300 margin-left: -1px;
301 background: var(--jaspers-foreground, #171717);
302}
303
304.yf-mark-hollow {
305 top: -5px;
306 width: 8px;
307 height: 8px;
308 margin-left: -4px;
309 margin-top: 1px;
310 background: var(--jaspers-background, #fff);
311 border: 2px solid var(--jaspers-muted-foreground, #737373);
312 box-sizing: border-box;
313}
314
315.yf-range-ends {
316 display: flex;
317 justify-content: space-between;
318 font-size: 12px;
319}
320
321.yf-grid {
322 display: grid;
323 grid-template-columns: repeat(auto-fill, minmax(128px, 1fr));
324 margin: 0;
325 border-top: 1px solid var(--jaspers-border, #e5e5e5);
326 border-left: 1px solid var(--jaspers-border, #e5e5e5);
327}
328
329.yf-cell {
330 padding: 4px 8px;
331 border-right: 1px solid var(--jaspers-border, #e5e5e5);
332 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
333 min-width: 0;
334}
335
336.yf-cell dt {
337 font-size: 12px;
338 white-space: nowrap;
339 overflow: hidden;
340 text-overflow: ellipsis;
341}
342
343.yf-cell dd {
344 margin: 0;
345 font-weight: 500;
346 white-space: nowrap;
347 overflow: hidden;
348 text-overflow: ellipsis;
349}
350
351.yf-legend {
352 display: flex;
353 flex-wrap: wrap;
354 align-items: center;
355 gap: 2px 12px;
356 margin: 2px 0 8px;
357 font-size: 12px;
358}
359
360.yf-key {
361 display: inline-block;
362 width: 9px;
363 height: 9px;
364 vertical-align: -1px;
365}
366
367.yf-key-solid {
368 width: 2px;
369 background: var(--jaspers-foreground, #171717);
370}
371
372.yf-key-hollow {
373 border: 2px solid var(--jaspers-muted-foreground, #737373);
374 box-sizing: border-box;
375}
376
377.yf-mix {
378 display: flex;
379 height: 10px;
380 margin: 4px 0 2px;
381 background: var(--jaspers-muted, #f5f5f5);
382}
383
384.yf-mix-strongBuy {
385 background: var(--jaspers-positive, #15803d);
386}
387
388.yf-mix-buy {
389 background: #86c79e;
390}
391
392.yf-mix-hold {
393 background: #d4d4d4;
394}
395
396.yf-mix-sell {
397 background: #e8a3a3;
398}
399
400.yf-mix-strongSell {
401 background: var(--jaspers-negative, #b91c1c);
402}
403
404.yf-summary {
405 margin: 6px 0 0;
406 max-width: 80ch;
407 color: var(--jaspers-foreground, #262626);
408}
409
410.yf-clamp {
411 display: -webkit-box;
412 -webkit-line-clamp: 4;
413 -webkit-box-orient: vertical;
414 overflow: hidden;
415}
416
417.yf-more {
418 color: var(--jaspers-muted-foreground, #737373);
419 font-size: 12px;
420 margin-top: 2px;
421}
422
423/* A fund's holdings beside its sector weights. */
424
425.yf-two {
426 display: grid;
427 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
428 gap: 4px 24px;
429 margin-top: 8px;
430}
431
432.yf-bars-title {
433 padding: 3px 0;
434 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
435 font-weight: 500;
436}
437
438.yf-bar-row {
439 display: grid;
440 grid-template-columns: minmax(120px, 40%) 1fr 56px;
441 align-items: center;
442 gap: 8px;
443 padding: 3px 0;
444 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
445}
446
447.yf-bar-label {
448 white-space: nowrap;
449 overflow: hidden;
450 text-overflow: ellipsis;
451}
452
453.yf-bar-track {
454 height: 8px;
455 background: var(--jaspers-muted, #f5f5f5);
456}
457
458.yf-bar-fill {
459 display: block;
460 height: 100%;
461 background: var(--jaspers-muted-foreground, #737373);
462}
463
464.yf-bar-row .yf-num {
465 text-align: right;
466}
467
468/* Markets. */
469
470.yf-tiles {
471 display: grid;
472 grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
473 border-top: 1px solid var(--jaspers-border, #e5e5e5);
474 border-left: 1px solid var(--jaspers-border, #e5e5e5);
475}
476
477.yf-tile {
478 display: flex;
479 flex-direction: column;
480 align-items: flex-start;
481 gap: 1px;
482 min-width: 0;
483 padding: 5px 8px;
484 border: 0;
485 border-right: 1px solid var(--jaspers-border, #e5e5e5);
486 border-bottom: 1px solid var(--jaspers-border, #e5e5e5);
487 background: var(--jaspers-background, #fff);
488 color: inherit;
489 text-align: left;
490 cursor: pointer;
491}
492
493.yf-tile:hover {
494 background: var(--jaspers-muted, #fafafa);
495}
496
497.yf-tile-up {
498 box-shadow: inset 0 2px 0 var(--jaspers-positive, #15803d);
499}
500
501.yf-tile-down {
502 box-shadow: inset 0 2px 0 var(--jaspers-negative, #b91c1c);
503}
504
505.yf-tile-name {
506 max-width: 100%;
507 font-size: 12px;
508 color: var(--jaspers-muted-foreground, #737373);
509 white-space: nowrap;
510 overflow: hidden;
511 text-overflow: ellipsis;
512}
513
514.yf-tile-price {
515 font-size: 15px;
516 font-weight: 600;
517}
518
519.yf-tile-move {
520 font-size: 12px;
521}
522
523/* Financials. */
524
525.yf-statement td:first-child {
526 white-space: normal;
527 min-width: 180px;
528}
529
530.yf-statement tr.yf-strong td {
531 font-weight: 600;
532}
533
534/* Options. */
535
536.yf-chain th.yf-side {
537 text-align: center;
538 color: var(--jaspers-foreground, #171717);
539 font-weight: 600;
540}
541
542.yf-chain .yf-strike,
543.yf-chain .yf-strike-head {
544 text-align: center !important;
545 font-weight: 600;
546 background: var(--jaspers-muted, #fafafa);
547 border-left: 1px solid var(--jaspers-border, #e5e5e5);
548 border-right: 1px solid var(--jaspers-border, #e5e5e5);
549}
550
551.yf-chain td.yf-itm {
552 background: var(--jaspers-muted, #f5f5f5);
553}
554
555/* Not the muted fill: a hovered row already turns muted, so a shaded cell goes a step past it. */
556.yf-chain tbody tr:hover td.yf-itm {
557 background: #eeeeee;
558}
559
560.yf-table tbody tr.yf-price-rule td,
561.yf-table tbody tr.yf-price-rule:hover td {
562 position: relative;
563 height: 18px;
564 padding: 0;
565 border-bottom: 0;
566 background: none;
567}
568
569.yf-price-rule td::before {
570 content: '';
571 position: absolute;
572 left: 0;
573 right: 0;
574 top: 50%;
575 border-top: 2px solid var(--jaspers-primary, #171717);
576}
577
578.yf-price-rule span {
579 position: absolute;
580 left: 50%;
581 top: 50%;
582 transform: translate(-50%, -50%);
583 line-height: 16px;
584 background: var(--jaspers-primary, #171717);
585 color: var(--jaspers-primary-foreground, #fff);
586 font-size: 11px;
587 padding: 0 6px;
588 white-space: nowrap;
589 font-variant-numeric: tabular-nums;
590}
591
592/* The plugin's own colours on the theme's dark background (#0a0a0a), each reading as its light value
593 does on white. The rating scale's middle steps are its dark ends dimmed toward the background, level
594 with each other, and hold a grey below them, so the ends stay the most intense; hold and a disabled
595 tab share a grey, as they do in light. */
596@media (prefers-color-scheme: dark) {
597 .yf-tab:disabled {
598 color: #404040;
599 }
600
601 .yf-x {
602 color: #525252;
603 }
604
605 .yf-mix-buy {
606 background: #2a7445;
607 }
608
609 .yf-mix-hold {
610 background: #404040;
611 }
612
613 .yf-mix-sell {
614 background: #a54d4d;
615 }
616
617 .yf-chain tbody tr:hover td.yf-itm {
618 background: #242424;
619 }
620}