@lightdash/cli 0.3480.0 → 0.3482.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -646,43 +646,49 @@ Lightdash-specific constraints that apply on top of `frontend-design`'s directio
|
|
|
646
646
|
|
|
647
647
|
- **Chart series colors must come from `CHART_COLORS` in `@/lib/theme`** — the canonical Lightdash palette, so generated apps' charts visually match native Lightdash dashboards. Cycle by index for multi-series (`CHART_COLORS[i % CHART_COLORS.length]`). `frontend-design`'s chosen accent/background/typography colors are independent of this.
|
|
648
648
|
- **Use semantic shadcn tokens for UI chrome** — `bg-background`, `bg-card`, `text-foreground`, `text-muted-foreground`, `text-destructive`, `border`, etc. Don't hardcode hex values for surfaces, text, or borders. (`frontend-design` may direct you to redefine the underlying CSS variables for a chosen theme — that's fine; the rule is no inline hex, not "use only the default token values".)
|
|
649
|
-
- **Commit to one theme; don't design for dark while rendering light.** The template's `:root` defaults to white (light tokens). If your design needs a dark background, you must do *one* of: (a) apply `className="dark"` to your top-level `<div>` so Tailwind activates the dark token values, or (b) override the CSS variables on `:root` directly to match your chosen theme. **Never** author colors that assume a dark background without ensuring the page actually loads dark — the symptom is invisible secondary text (faint red/gray on white). Before declaring done, check: does the page background actually look the way you described it? If not, you have a theme-wiring bug.
|
|
649
|
+
- **Commit to one theme; don't design for dark while rendering light.** The template's `:root` defaults to white (light tokens). If your design needs a dark background, you must do *one* of: (a) apply `className="dark bg-background text-foreground"` to your top-level `<div>` so Tailwind activates the dark token values *and* re-resolves the inherited text color there, or (b) override the CSS variables on `:root` directly to match your chosen theme. **Never** author colors that assume a dark background without ensuring the page actually loads dark — the symptom is invisible secondary text (faint red/gray on white). Before declaring done, check: does the page background actually look the way you described it? If not, you have a theme-wiring bug.
|
|
650
650
|
- **Theme CSS variables hold complete raw colors, consumed as `var(--x)`.** The template's tokens are `oklch(…)` values, and everything — Tailwind utilities, the floating-surface chrome, your own CSS — reads them with plain `var(--x)`. When overriding on `:root`, write full CSS colors (`--background: oklch(0.14 0.005 286);` — any valid color works). **Never write bare `H S% L%` triplets and never wrap a variable in `hsl(var(--x))`** — both come from a different shadcn convention this template does not use; they produce invalid CSS that browsers silently drop, which breaks text colors or turns popovers/tooltips transparent.
|
|
651
|
-
- **
|
|
651
|
+
- **The page background must reach the bottom of the iframe.** Viewers render the app in an iframe as tall as their browser window, and app content is routinely shorter than that. So structure every page as a **full-height themed shell** (theme class, background, `text-foreground`, `min-h-screen`) wrapping a **content-sized inner wrapper** that owns the padding — see the example in the next section. Putting the background on a content-sized element instead leaves everything below it painting the template default: a hard edge across the page where your theme stops, and the single most common way a generated app reads as broken. Never paint the page background on `#root` or `body` instead; they sit outside your theme.
|
|
652
|
+
- **Leave a gutter at the bottom of the content.** Don't let the last card, chart, or footer sit flush against the bottom edge — it reads as clipped. Put the bottom padding (`pb-8` or similar) on the inner wrapper, so the gutter sits inside both the theme and the screenshot bounds.
|
|
652
653
|
|
|
653
654
|
### Sizing for scheduled-delivery screenshots
|
|
654
655
|
|
|
655
|
-
Scheduled deliveries (Slack/email) render the app inside a tall **1400×4000** iframe and screenshot from the top down to the
|
|
656
|
+
Scheduled deliveries (Slack/email) render the app inside a tall **1400×4000** iframe and screenshot from the top down to the bottom of the content. If the *content* stretches to fill that height — via viewport-relative heights or full-bleed decorative layers in the flow — the delivered image is mostly empty space around a small island of content.
|
|
656
657
|
|
|
657
|
-
|
|
658
|
-
**Mark the content extent with `data-screenshot-bounds`.** Put the attribute on your top-level themed wrapper — the same element that carries the background and bottom gutter from the rule above. The delivery pipeline uses that element's bottom edge as the image height and crops anything below it. Without the attribute it falls back to a best-effort measurement that the patterns below easily inflate, so set it.
|
|
658
|
+
**Mark the content extent with `data-screenshot-bounds`.** Put the attribute on the inner content wrapper from the rule above — **not** on the full-height shell. The delivery pipeline uses that element's bottom edge as the image height and crops everything below it, which is exactly why the shell may fill the iframe for free: the shell's `min-h-screen` never reaches the delivered image, and the crop still lands just under your last row. Without the attribute the pipeline falls back to a best-effort measurement that the patterns below easily inflate, so set it.
|
|
659
659
|
|
|
660
660
|
```tsx
|
|
661
|
-
<div
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
661
|
+
<div className="dark bg-background text-foreground min-h-screen"> {/* fills the viewport, not measured */}
|
|
662
|
+
<div data-screenshot-bounds className="p-8 pb-12"> {/* measured: crop lands here */}
|
|
663
|
+
<Header />
|
|
664
|
+
<ChartGrid />
|
|
665
|
+
<Footer />
|
|
666
|
+
</div>
|
|
666
667
|
</div>
|
|
667
668
|
```
|
|
668
669
|
|
|
669
|
-
|
|
670
|
+
`text-foreground` on the shell is not optional: `dark` re-points the theme variables but not the `color` already inherited from `<body>`, so without it every bare `<h1>`/`<p>`/`<div>` renders in light-theme ink on your dark background.
|
|
670
671
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
- **
|
|
672
|
+
Then keep the content from inflating the canvas:
|
|
673
|
+
|
|
674
|
+
- **No viewport-relative heights inside the bounds element** — avoid `min-h-screen`, `h-screen`, `h-[100vh]`, or `min-height: 100vh` on the content wrapper or anything in its flow; let it size to its content. A nested component that genuinely needs a fixed height (e.g. a resizable panel) may still use one. The page's only viewport height belongs to the shell, outside `data-screenshot-bounds`.
|
|
675
|
+
- **Don't vertically center variable-height content in a viewport-height parent** — `min-h-screen flex items-center justify-center` around a short widget parks it in the middle of a 4000px-tall canvas, and the crop keeps every empty pixel above it. Top-align content in the shell and let the shell grow.
|
|
676
|
+
- **Keep decorative backgrounds out of the flow** — themed sprites, gradients, particle layers, and landscape art paint on the shell itself or on a `fixed inset-0 -z-10` layer, never as an in-flow 100vh element inside the bounds.
|
|
674
677
|
|
|
675
678
|
Avoid — each of these inflates the screenshot:
|
|
676
679
|
|
|
677
680
|
```tsx
|
|
678
|
-
//
|
|
679
|
-
<div className="min-h-screen bg-blue-400">…</div>
|
|
681
|
+
// crop marker on a viewport-height element → 4000px of empty canvas
|
|
682
|
+
<div data-screenshot-bounds className="min-h-screen bg-blue-400">…</div>
|
|
680
683
|
|
|
681
684
|
// a short widget centered in 100vh ends up mid-screenshot
|
|
682
|
-
<div className="h-screen flex items-center justify-center"><SmallWidget /></div>
|
|
685
|
+
<div className="min-h-screen flex items-center justify-center"><SmallWidget /></div>
|
|
683
686
|
|
|
684
|
-
//
|
|
685
|
-
<div
|
|
687
|
+
// an in-flow decorative layer that outgrows the real content
|
|
688
|
+
<div data-screenshot-bounds>
|
|
689
|
+
<div className="h-screen bg-[url('/sky.png')] bg-cover" />
|
|
690
|
+
<Dashboard />
|
|
691
|
+
</div>
|
|
686
692
|
```
|
|
687
693
|
|
|
688
694
|
### Organization themes
|
|
@@ -78,4 +78,29 @@
|
|
|
78
78
|
html, body {
|
|
79
79
|
@apply bg-background text-foreground;
|
|
80
80
|
}
|
|
81
|
+
/* Safety net for pages that theme a content-sized wrapper instead of a
|
|
82
|
+
full-height shell (see skill.md) — otherwise the iframe area below the
|
|
83
|
+
content paints the template default as a hard edge. Wrapped in :where() so
|
|
84
|
+
anything the app sets itself still wins. */
|
|
85
|
+
:where(#root > :first-child:not([data-screenshot-bounds])) {
|
|
86
|
+
min-height: 100vh;
|
|
87
|
+
}
|
|
88
|
+
/* The crop marker defines the delivery-screenshot height, so it can't be
|
|
89
|
+
stretched — repaint its background behind the whole viewport instead.
|
|
90
|
+
`fixed` on both layers keeps a gradient from seaming at the content edge. */
|
|
91
|
+
:where(#root > [data-screenshot-bounds]:first-child) {
|
|
92
|
+
background-attachment: fixed;
|
|
93
|
+
}
|
|
94
|
+
#root > [data-screenshot-bounds]:first-child::before {
|
|
95
|
+
content: '';
|
|
96
|
+
position: fixed;
|
|
97
|
+
inset: 0;
|
|
98
|
+
z-index: -1;
|
|
99
|
+
background: inherit;
|
|
100
|
+
}
|
|
101
|
+
/* `dark` on the shell re-points the theme variables but not the color already
|
|
102
|
+
inherited from <body>, which would leave bare text in light-theme ink. */
|
|
103
|
+
:where(#root > .dark:first-child) {
|
|
104
|
+
color: var(--foreground);
|
|
105
|
+
}
|
|
81
106
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3482.0",
|
|
4
4
|
"description": "Lightdash CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"unique-names-generator": "4.7.1",
|
|
42
42
|
"uuid": "11.1.1",
|
|
43
43
|
"yaml": "2.8.3",
|
|
44
|
-
"@lightdash/
|
|
45
|
-
"@lightdash/
|
|
44
|
+
"@lightdash/warehouses": "0.3482.0",
|
|
45
|
+
"@lightdash/common": "0.3482.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/inquirer": "8.2.4",
|