eco-vue-js 0.20.1 → 0.20.3

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.
@@ -1,4 +1,5 @@
1
1
  import { LinkProps } from '../../types/types';
2
+ import { SemanticType } from '../../utils/SemanticType';
2
3
  interface Props extends Partial<LinkProps> {
3
4
  /** Label. The `default` slot replaces it. */
4
5
  text?: string;
@@ -12,6 +13,8 @@ interface Props extends Partial<LinkProps> {
12
13
  download?: string;
13
14
  /** Tooltip over the item. */
14
15
  tooltipText?: string;
16
+ /** Color of the item. Types other than `primary` and `secondary` color the text at rest — a red "Delete". */
17
+ semanticType?: SemanticType;
15
18
  }
16
19
  type __VLS_Slots = {
17
20
  /** Label. Replaces `text`. */
@@ -1 +1 @@
1
- {"version":3,"file":"WButtonMoreItem.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/Button/WButtonMoreItem.vue"],"names":[],"mappings":"AAyBA;AA6DA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAA;AAI5C,UAAU,KAAM,SAAQ,OAAO,CAAC,SAAS,CAAC;IACxC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAWD,KAAK,WAAW,GAAG;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,IAAI,CAAA;CAClB,CAAC;AA6EF,QAAA,MAAM,UAAU;;;;kFAGd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"WButtonMoreItem.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/Button/WButtonMoreItem.vue"],"names":[],"mappings":"AA0BA;AAiEA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,sBAAsB,CAAA;AAItD,UAAU,KAAM,SAAQ,OAAO,CAAC,SAAS,CAAC;IACxC,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6GAA6G;IAC7G,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B;AAWD,KAAK,WAAW,GAAG;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,MAAM,IAAI,CAAA;CAClB,CAAC;AA+EF,QAAA,MAAM,UAAU;;;;kFAGd,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -11,6 +11,7 @@ var WButtonMoreItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
11
11
  href: {},
12
12
  download: {},
13
13
  tooltipText: {},
14
+ semanticType: {},
14
15
  to: {}
15
16
  },
16
17
  emits: ["click"],
@@ -22,6 +23,7 @@ var WButtonMoreItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
22
23
  download: __props.download,
23
24
  disabled: __props.disabled,
24
25
  "tooltip-text": __props.tooltipText,
26
+ "semantic-type": __props.semanticType,
25
27
  onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("click", $event))
26
28
  }, {
27
29
  default: withCtx(() => [createElementVNode("div", _hoisted_1, [renderSlot(_ctx.$slots, "default", {}, () => [createTextVNode(toDisplayString(__props.text), 1)])]), renderSlot(_ctx.$slots, "icon", {}, () => [__props.icon ? (openBlock(), createBlock(resolveDynamicComponent(__props.icon), {
@@ -34,7 +36,8 @@ var WButtonMoreItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
34
36
  "href",
35
37
  "download",
36
38
  "disabled",
37
- "tooltip-text"
39
+ "tooltip-text",
40
+ "semantic-type"
38
41
  ]);
39
42
  };
40
43
  }
@@ -11,7 +11,7 @@ var HeatmapCell_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defi
11
11
  const tooltipRef = useTemplateRef("tooltip");
12
12
  return (_ctx, _cache) => {
13
13
  return openBlock(), createElementBlock("div", { class: normalizeClass(["group/cell relative rounded-sm p-(--w-chart-heatmap-gap,0.125rem)", __props.opacity !== null ? "cursor-crosshair" : void 0]) }, [createElementVNode("div", {
14
- class: normalizeClass(["size-(--w-chart-heatmap-size,1rem) rounded-sm", __props.empty ? void 0 : __props.opacity !== null ? "bg-current" : "bg-surface-muted/50"]),
14
+ class: normalizeClass(["size-(--w-chart-heatmap-size,1rem) rounded-sm", __props.empty ? void 0 : __props.opacity !== null ? "bg-current" : "bg-surface-subtle"]),
15
15
  style: normalizeStyle(__props.opacity !== null && !__props.empty ? { opacity: __props.opacity } : void 0)
16
16
  }, null, 6), _ctx.$slots.default && __props.opacity !== null ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createElementVNode("div", { class: normalizeClass(["absolute inset-(--w-chart-heatmap-gap,0.125rem) rounded-sm border-current group-hover/cell:border-2", tooltipRef.value?.isOpen ? "border-2" : void 0]) }, null, 2), createVNode(WTooltip_default, {
17
17
  ref: "tooltip",
@@ -150,7 +150,7 @@ var ListItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineC
150
150
  class: ["relative", {
151
151
  [__props.cardWrapperClass ?? ""]: true,
152
152
  "w-ripple-trigger-list": isActionShown.value,
153
- "sm-not:even:bg-surface-muted/50 grid grid-cols-1": __props.card,
153
+ "sm-not:even:bg-surface-subtle grid grid-cols-1": __props.card,
154
154
  "flex": !__props.card,
155
155
  "-mb-px": !__props.card && isOpen.value,
156
156
  "w-hover-checked": __props.allowSelectHover
@@ -1,4 +1,5 @@
1
1
  import { LinkProps } from '../../types/types';
2
+ import { SemanticType } from '../../utils/SemanticType';
2
3
  interface Props extends Partial<LinkProps> {
3
4
  /** Grays the item out and ignores clicks. */
4
5
  disabled?: boolean;
@@ -12,6 +13,8 @@ interface Props extends Partial<LinkProps> {
12
13
  tooltipText?: string;
13
14
  /** Shows a spinner over the item and ignores clicks. */
14
15
  loading?: boolean;
16
+ /** Color of the item. Types other than `primary` and `secondary` color the text at rest — a red "Delete". */
17
+ semanticType?: SemanticType;
15
18
  }
16
19
  type __VLS_Slots = {
17
20
  /** Content of the item, laid out in a row. */
@@ -22,6 +25,7 @@ declare const __VLS_base: import('vue').DefineComponent<Props, {}, {}, {}, {}, i
22
25
  }, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
23
26
  onClick?: ((value: MouseEvent) => any) | undefined;
24
27
  }>, {
28
+ semanticType: SemanticType;
25
29
  href: string;
26
30
  active: boolean;
27
31
  tooltipText: string;
@@ -1 +1 @@
1
- {"version":3,"file":"WMenuItem.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/MenuItem/WMenuItem.vue"],"names":[],"mappings":"AA0DA;AAyGA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAA;AAS5C,UAAU,KAAM,SAAQ,OAAO,CAAC,SAAS,CAAC;IACxC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gIAAgI;IAChI,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAmBD,KAAK,WAAW,GAAG;IACjB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,CAAC;AAsMF,QAAA,MAAM,UAAU;;;;;UArOP,MAAM;YAIJ,OAAO;iBAEF,MAAM;cAJT,MAAM;6EAuOjB,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
1
+ {"version":3,"file":"WMenuItem.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/MenuItem/WMenuItem.vue"],"names":[],"mappings":"AA4DA;AAsHA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,eAAe,CAAA;AAS5C,OAAO,EAAC,YAAY,EAAyB,MAAM,sBAAsB,CAAA;AAIzE,UAAU,KAAM,SAAQ,OAAO,CAAC,SAAS,CAAC;IACxC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gIAAgI;IAChI,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wDAAwD;IACxD,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,6GAA6G;IAC7G,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B;AAoBD,KAAK,WAAW,GAAG;IACjB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB,CAAC;AAgNF,QAAA,MAAM,UAAU;;;;;kBAxOC,YAAY;UAVpB,MAAM;YAIJ,OAAO;iBAEF,MAAM;cAJT,MAAM;6EAoPjB,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
@@ -1,8 +1,9 @@
1
+ import { SemanticType, useSemanticTypeTextMap } from "../../utils/SemanticType.js";
1
2
  import WRouterLink_default from "../RouterLink/WRouterLink.vue.js";
2
3
  import WTooltip_default from "../Tooltip/WTooltip.vue.js";
3
4
  import WSpinner_default from "../Spinner/WSpinner.vue.js";
4
5
  import IconCheck_default from "../../assets/icons/IconCheck.js";
5
- import { Transition, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderSlot, resolveDynamicComponent, unref, withCtx } from "vue";
6
+ import { Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, normalizeClass, openBlock, renderSlot, resolveDynamicComponent, unref, withCtx } from "vue";
6
7
  //#region src/components/MenuItem/WMenuItem.vue?vue&type=script&setup=true&lang.ts
7
8
  var _hoisted_1 = { class: "flex items-center gap-4" };
8
9
  var _hoisted_2 = {
@@ -25,20 +26,26 @@ var WMenuItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
25
26
  },
26
27
  tooltipText: { default: void 0 },
27
28
  loading: { type: Boolean },
29
+ semanticType: { default: SemanticType.PRIMARY },
28
30
  to: {}
29
31
  },
30
32
  emits: ["click"],
31
33
  setup(__props) {
34
+ const props = __props;
35
+ const semanticTypeTextMap = useSemanticTypeTextMap();
36
+ const toned = computed(() => props.semanticType !== SemanticType.PRIMARY && props.semanticType !== SemanticType.SECONDARY);
32
37
  return (_ctx, _cache) => {
33
38
  return openBlock(), createBlock(resolveDynamicComponent(__props.disabled || __props.loading ? "div" : __props.to ? WRouterLink_default : __props.href ? "a" : "button"), mergeProps(__props.disabled || __props.loading ? void 0 : __props.to ? { to: __props.to } : __props.href ? {
34
39
  href: __props.href,
35
40
  download: __props.download
36
41
  } : void 0, {
37
42
  class: ["w-ripple-trigger relative block w-full select-none items-center justify-start px-2 text-start outline-none first:pt-2 last:pb-2", {
38
- "tone-primary hover:text-tone cursor-pointer": !__props.disabled && !__props.loading,
43
+ [unref(semanticTypeTextMap)[__props.semanticType]]: toned.value && !__props.disabled,
44
+ "tone-primary": !toned.value,
45
+ "hover:text-tone cursor-pointer": !__props.disabled && !__props.loading,
39
46
  "cursor-not-allowed opacity-50": __props.disabled,
40
- "tone-primary text-tone": __props.active && !__props.disabled,
41
- "text-description": !__props.active || __props.disabled,
47
+ "text-tone": __props.active && !__props.disabled,
48
+ "text-description": !__props.active && !toned.value || __props.disabled,
42
49
  "cursor-progress": __props.loading
43
50
  }],
44
51
  disabled: __props.disabled,
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/rsmple/eco-vue-js.git"
6
6
  },
7
- "version": "0.20.1",
7
+ "version": "0.20.3",
8
8
  "homepage": "https://rsmple.github.io/eco-vue-js/",
9
9
  "dependencies": {
10
10
  "@stylistic/eslint-plugin": "5.10.0",
@@ -7,6 +7,7 @@
7
7
  * 'border-gray-300 dark:border-gray-700' → 'border-line'
8
8
  * 'text-negative dark:text-negative-dark' → 'tone-negative text-tone'
9
9
  * 'bg-primary/10 dark:bg-primary-dark/10' → 'tone-primary bg-tone-fill/10'
10
+ * 'bg-primary-light dark:bg-primary-darkest' → 'tone-primary bg-tone-soft'
10
11
  *
11
12
  * npx eco-vue-color-roles [--write] [--exact] [--theme <css>] [paths…] default: src
12
13
  *
@@ -37,6 +38,7 @@ const ROLES = [
37
38
  {role: 'text-description', color: 'description', props: TEXT_PROPS, light: 'gray-500', dark: 'gray-400'},
38
39
  {role: 'text-subtle', color: 'subtle', props: TEXT_PROPS, light: 'gray-400', dark: 'gray-600'},
39
40
  {role: 'surface', color: 'surface', props: [...SURFACE_PROPS, 'text'], light: 'default', dark: 'default-dark'},
41
+ {role: 'surface-subtle', color: 'surface-subtle', props: SURFACE_PROPS, light: 'gray-50', dark: 'gray-850'},
40
42
  {role: 'surface-muted', color: 'surface-muted', props: SURFACE_PROPS, light: 'gray-100', dark: 'gray-800'},
41
43
  {role: 'surface-inset', color: 'surface-inset', props: SURFACE_PROPS, light: 'gray-200', dark: 'gray-700'},
42
44
  {role: 'track', color: 'track', props: ['bg', 'fill', 'stroke'], light: 'gray-300', dark: 'gray-700'},
@@ -59,6 +61,11 @@ const NEUTRAL_UNIFIED = {
59
61
  'border:gray-200|gray-800': 'border-line-subtle', // dark 800 → 700
60
62
  // Exactly `line-raised`, but in app code these are card borders, not the edge of a popup.
61
63
  'border:gray-100|gray-800': 'border-line-subtle', // light 100 → 200, dark 800 → 700
64
+ // Half of `surface-muted` over the surface, which is what `gray-850` is in dark mode.
65
+ 'bg:gray-50|gray-800/50': 'bg-surface-subtle',
66
+ 'bg:gray-50|gray-800/40': 'bg-surface-subtle', // dark a bit stronger
67
+ 'bg:gray-100/50|gray-800/50': 'bg-surface-subtle',
68
+ 'bg:gray-50|gray-800': 'bg-surface-muted', // light 50 → 100
62
69
  }
63
70
 
64
71
  /**
@@ -157,11 +164,16 @@ const transformClasses = (value, exact, table) => {
157
164
  } else {
158
165
  const tone = TONES.find(item => lightColor === item && darkColor === item + '-dark' && lightAlpha === darkAlpha)
159
166
  const toneProp = TONE_PROPS[/** @type {keyof typeof TONE_PROPS} */ (light.prop)]
167
+ // `bg-primary-light dark:bg-primary-darkest` is the soft background, which the tone mixes from its fill.
168
+ const soft = light.prop === 'bg' && TONES.find(item => lightColor === item + '-light' && darkColor === item + '-darkest' && lightAlpha === darkAlpha)
160
169
 
161
170
  // A tone is set on the whole string, so only strings with one tone and no state variant on it qualify.
162
171
  if (tone && toneProp && (toneProp.exact || !exact) && !light.variants && tonesInString.size === 1) {
163
172
  next = toneProp.utility + alpha
164
173
  addTone = 'tone-' + tone
174
+ } else if (soft && !exact && !light.variants && tonesInString.size === 1) {
175
+ next = 'bg-tone-soft' + alpha
176
+ addTone = 'tone-' + soft
165
177
  }
166
178
  }
167
179
 
@@ -173,14 +185,19 @@ const transformClasses = (value, exact, table) => {
173
185
  replaced.push(`${ light.raw } ${ dark.raw } → ${ next }`)
174
186
  words[index] = next
175
187
  words[darkIndex] = ''
188
+ // The removed class takes one separator with it: the one before, unless it starts the string or a line. Lines and
189
+ // their indentation stay as they were.
190
+ const before = words[darkIndex - 1]
191
+ const dropAfter = darkIndex === 0 || (before?.includes('\n') && darkIndex + 1 < words.length)
192
+
193
+ words[dropAfter ? darkIndex + 1 : darkIndex - 1] = ''
176
194
  tokens[index] = null
177
195
  tokens[darkIndex] = null
178
196
  })
179
197
 
180
- // Removed classes leave gaps: collapse them, drop spaces left before line breaks, keep the string's own edges.
181
- const lead = value.match(/^\s*/)?.[0] ?? ''
182
- const trail = value.match(/\s*$/)?.[0] ?? ''
183
- let text = lead + words.join('').trim().replace(/[ \t]{2,}/g, ' ').replace(/[ \t]+\n/g, '\n') + trail
198
+ if (!replaced.length) return {text: value, replaced, unmapped, left: tokens.filter(token => token !== null).map(token => token.raw)}
199
+
200
+ let text = words.join('')
184
201
 
185
202
  if (addTone && !text.split(/\s+/).includes(addTone)) text = text.replace(/^(\s*)/, `$1${ addTone } `)
186
203
 
@@ -0,0 +1,127 @@
1
+ /*
2
+ * Markdown blocks beyond plain markdown, as GitBook writes them: hints, colored text, expandable sections, embedded
3
+ * videos and quotes with an avatar. A renderer outputs this markup itself:
4
+ *
5
+ * - `.hint-{info|success|warning|danger|note}`: a callout box.
6
+ * - `mark.mark-{blue|green|red|danger|orange|purple}`: colored text; `mark.mark-{blue|green|red}-bg`: a colored
7
+ * highlight.
8
+ * - `details > summary > div`: an expandable section; consecutive sections join into one bordered group.
9
+ * - `.markdown-embed-video > iframe`, `.markdown-table > div > table` (scrolls sideways), `cite > img + …`,
10
+ * `img[data-size="line"]` (an inline image as tall as the text).
11
+ */
12
+ @layer components {
13
+ .w-markdown :is(.hint-info, .mark-blue, .mark-blue-bg) {
14
+ @apply tone-info;
15
+ }
16
+
17
+ .w-markdown :is(.hint-success, .mark-green, .mark-green-bg) {
18
+ @apply tone-positive;
19
+ }
20
+
21
+ .w-markdown :is(.hint-warning, .mark-orange) {
22
+ @apply tone-warning;
23
+ }
24
+
25
+ .w-markdown :is(.hint-danger, .mark-red, .mark-danger, .mark-red-bg) {
26
+ @apply tone-negative;
27
+ }
28
+
29
+ .w-markdown .mark-purple {
30
+ @apply tone-primary;
31
+ }
32
+
33
+ .w-markdown :is(.hint-info, .hint-success, .hint-warning, .hint-danger, .mark-blue, .mark-green, .mark-orange, .mark-red, .mark-danger, .mark-purple) {
34
+ @apply bg-tone-soft text-tone;
35
+ }
36
+
37
+ .w-markdown :is(.mark-blue-bg, .mark-green-bg, .mark-red-bg) {
38
+ @apply bg-tone-fill/40;
39
+ }
40
+
41
+ .w-markdown .hint-note {
42
+ @apply bg-surface-muted text-description;
43
+ }
44
+
45
+ .w-markdown details {
46
+ @apply bg-surface border-line relative border-x border-t border-solid p-4;
47
+ }
48
+
49
+ .w-markdown details:first-of-type {
50
+ @apply rounded-t-lg;
51
+ }
52
+
53
+ .w-markdown details:last-of-type {
54
+ @apply mb-4 rounded-b-lg border-b;
55
+ }
56
+
57
+ .w-markdown details > div {
58
+ display: grid;
59
+ }
60
+
61
+ .w-markdown details > :nth-child(2) {
62
+ margin-top: 2rem;
63
+ }
64
+
65
+ /* Sticks to the top of the scroll container while its section scrolls, covering the content above it. */
66
+ .w-markdown summary {
67
+ z-index: 3;
68
+ margin: -10rem -1rem -1rem;
69
+ @apply text-description hover:text-accent sticky -top-20 cursor-pointer list-none pt-36 select-none;
70
+ }
71
+
72
+ .w-markdown summary > div {
73
+ grid-template-columns: auto 1fr auto;
74
+ @apply bg-surface relative grid gap-4 rounded-md p-4;
75
+ }
76
+
77
+ .w-markdown summary svg {
78
+ @apply transition-transform self-center;
79
+ }
80
+
81
+ .w-markdown details:open summary svg {
82
+ @apply rotate-0;
83
+ }
84
+
85
+ .w-markdown .markdown-embed-video {
86
+ margin-block: 1em;
87
+ @apply aspect-video w-full;
88
+ }
89
+
90
+ .w-markdown .markdown-embed-video iframe {
91
+ @apply size-full;
92
+ }
93
+
94
+ .w-markdown .markdown-table,
95
+ .w-markdown .markdown-table > div {
96
+ display: grid;
97
+ }
98
+
99
+ .w-markdown .markdown-table > div {
100
+ @apply not-print:overflow-x-auto;
101
+ }
102
+
103
+ .w-markdown cite {
104
+ display: grid;
105
+ grid-template-columns: auto 1fr;
106
+ align-items: center;
107
+ column-gap: 1rem;
108
+ margin-bottom: 1rem;
109
+ padding-left: 1.5rem;
110
+ }
111
+
112
+ .w-markdown cite :not(img) {
113
+ width: 100%;
114
+ }
115
+
116
+ .w-markdown cite img {
117
+ grid-row: 1 / 4;
118
+ height: 4.5rem;
119
+ margin-bottom: 0;
120
+ }
121
+
122
+ .w-markdown img[data-size="line"] {
123
+ display: inline;
124
+ height: 1.75em;
125
+ margin-bottom: 0;
126
+ }
127
+ }
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Markdown code blocks: `pre > code`, one `.line` per line (numbered by the kit's textarea styles). An optional header
3
+ * before the `code` — `pre > div:first-child`, holding the language and a `.button-copy-code` — sits over its top
4
+ * padding.
5
+ */
6
+ @layer components {
7
+ .w-markdown pre {
8
+ position: relative;
9
+ display: grid;
10
+ white-space: pre;
11
+ word-break: break-word;
12
+ background-color: var(--w-input-bg, inherit);
13
+ @apply mb-3 overflow-x-auto overscroll-x-contain rounded-xl border border-solid border-line-subtle
14
+ print:whitespace-pre-wrap print:break-all;
15
+ }
16
+
17
+ .w-markdown pre code {
18
+ font-size: inherit;
19
+ color: inherit;
20
+ @apply px-3 py-3 first-not:pt-8 rounded-inherit overscroll-x-contain
21
+ not-print:max-h-[calc(100vh-6rem)] not-print:overflow-auto;
22
+ }
23
+
24
+ .w-markdown pre code .line {
25
+ @apply -mx-3;
26
+ }
27
+
28
+ .w-markdown pre code .line::before {
29
+ @apply pl-3 -left-3;
30
+ }
31
+
32
+ .w-markdown pre > div:first-child {
33
+ background: inherit;
34
+ @apply text-description absolute inset-x-0 top-0 flex items-end justify-between gap-2 pt-2 pb-1 pl-3 text-xs;
35
+ }
36
+
37
+ .w-markdown .button-copy-code {
38
+ @apply hover:text-accent -mt-2 -mb-1 flex items-center gap-2 px-3 pt-2 pb-1 print:hidden;
39
+ }
40
+
41
+ .w-markdown.w-report pre {
42
+ overflow-x: unset;
43
+ @apply bg-surface-subtle text-accent whitespace-pre-wrap break-all;
44
+ }
45
+
46
+ .w-markdown.enable-mobile pre {
47
+ @apply sm-not:px---inner-margin sm-not:border-x-0 sm-not:rounded-none;
48
+ }
49
+ }
@@ -0,0 +1,156 @@
1
+ /*
2
+ * Markdown text: what any renderer outputs inside `.w-markdown` — headings, paragraphs, lists, quotes, links, inline
3
+ * code, tables and images. Sizes are in `em`, so the content follows the container's font size.
4
+ *
5
+ * Modifiers on `.w-markdown`:
6
+ * - `enable-mobile`: below `sm`, text keeps the page's inner margin while code blocks and tables reach the screen edges.
7
+ * - `w-report`: for print — code wraps and its lines don't highlight on hover.
8
+ */
9
+ @layer components {
10
+ .w-markdown {
11
+ isolation: isolate;
12
+ }
13
+
14
+ .w-markdown :is(h1, h2, h3, h4, h5, h6) {
15
+ margin-block: 0.75em 0.5em;
16
+ @apply font-medium;
17
+ }
18
+
19
+ .w-markdown h1 {
20
+ font-size: 1.875em;
21
+ line-height: 2.25em;
22
+ }
23
+
24
+ .w-markdown h2 {
25
+ font-size: 1.5em;
26
+ line-height: 2em;
27
+ }
28
+
29
+ .w-markdown h3 {
30
+ font-size: 1.25em;
31
+ line-height: 1.75em;
32
+ }
33
+
34
+ .w-markdown h4 {
35
+ font-size: 1.125em;
36
+ line-height: 1.75em;
37
+ margin-block: 0.5em;
38
+ }
39
+
40
+ .w-markdown h5 {
41
+ font-size: 1em;
42
+ line-height: 1.5em;
43
+ margin-block: 0.5em;
44
+ }
45
+
46
+ .w-markdown h6 {
47
+ font-size: 0.75em;
48
+ line-height: 1em;
49
+ margin-block: 0.5em;
50
+ @apply font-semibold;
51
+ }
52
+
53
+ .w-markdown p {
54
+ word-break: break-word;
55
+ @apply last-not:mb-[0.75em];
56
+ }
57
+
58
+ .w-markdown a {
59
+ @apply tone-primary text-tone underline;
60
+ }
61
+
62
+ .w-markdown hr {
63
+ margin-block: 1.25em;
64
+ @apply border-line;
65
+ }
66
+
67
+ .w-markdown :is(ul, ol) {
68
+ padding-inline-start: 2.5em;
69
+ margin-bottom: 0.75em;
70
+ }
71
+
72
+ .w-markdown :is(ul, ol) :is(ul, ol) {
73
+ margin-inline: 0;
74
+ }
75
+
76
+ .w-markdown ul {
77
+ list-style-type: disc;
78
+ }
79
+
80
+ .w-markdown ul ul {
81
+ list-style-type: circle;
82
+ }
83
+
84
+ .w-markdown ul ul ul {
85
+ list-style-type: square;
86
+ }
87
+
88
+ .w-markdown ol {
89
+ list-style-type: decimal;
90
+ }
91
+
92
+ .w-markdown blockquote {
93
+ margin-bottom: 0.75em;
94
+ padding: 0.5em 1.25em;
95
+ @apply border-l-4 border-solid border-line-subtle italic;
96
+ }
97
+
98
+ .w-markdown :not(pre) > code {
99
+ font-size: 90%;
100
+ @apply tone-primary bg-tone-soft text-tone px-1 rounded-sm;
101
+ }
102
+
103
+ .w-markdown mark {
104
+ font-size: 90%;
105
+ @apply tone-warning bg-tone-fill/50 text-accent font-mono px-1 py-0.5 rounded-sm;
106
+ }
107
+
108
+ .w-markdown mark code {
109
+ background: unset;
110
+ color: unset;
111
+ padding: unset;
112
+ }
113
+
114
+ .w-markdown table {
115
+ margin-bottom: 1.25em;
116
+ @apply w-full;
117
+ }
118
+
119
+ .w-markdown :is(th, td) {
120
+ padding: 0.5em;
121
+ }
122
+
123
+ .w-markdown th {
124
+ @apply text-description font-semibold text-left;
125
+ }
126
+
127
+ .w-markdown tbody tr {
128
+ @apply border-t border-solid border-line-subtle;
129
+ }
130
+
131
+ .w-markdown tbody tr:nth-child(odd) {
132
+ @apply bg-surface-subtle;
133
+ }
134
+
135
+ .w-markdown img {
136
+ display: block;
137
+ object-fit: contain;
138
+ margin-bottom: 1em;
139
+ }
140
+
141
+ .w-markdown :is(p, figure) > img {
142
+ @apply sm-not:-mx-4 sm-not:w-screen sm-not:max-w-screen;
143
+ }
144
+
145
+ .w-markdown.enable-mobile > :is(h1, h2, h3, h4, h5, h6) {
146
+ @apply sm-not:px---inner-margin;
147
+ }
148
+
149
+ .w-markdown.enable-mobile > :is(p, ul, ol, blockquote) {
150
+ @apply sm-not:mx---inner-margin;
151
+ }
152
+
153
+ .w-markdown.enable-mobile :is(th, td) {
154
+ @apply sm-not:first:pl---inner-margin sm-not:last:pr---inner-margin;
155
+ }
156
+ }
@@ -21,6 +21,8 @@
21
21
 
22
22
  --role-surface: var(--color-default);
23
23
  --role-surface-dark: var(--color-default-dark);
24
+ --role-surface-subtle: var(--color-gray-50);
25
+ --role-surface-subtle-dark: var(--color-gray-850);
24
26
  --role-surface-muted: var(--color-gray-100);
25
27
  --role-surface-muted-dark: var(--color-gray-800);
26
28
  --role-surface-inset: var(--color-gray-200);
@@ -59,6 +61,7 @@
59
61
  --color-subtle: var(--w-text-subtle);
60
62
 
61
63
  --color-surface: var(--w-surface);
64
+ --color-surface-subtle: var(--w-surface-subtle);
62
65
  --color-surface-muted: var(--w-surface-muted);
63
66
  --color-surface-inset: var(--w-surface-inset);
64
67
  --color-overlay: var(--w-overlay);
@@ -112,6 +115,7 @@
112
115
  --w-text-subtle: light-dark(var(--role-text-subtle), var(--role-text-subtle-dark));
113
116
 
114
117
  --w-surface: light-dark(var(--role-surface), var(--role-surface-dark));
118
+ --w-surface-subtle: light-dark(var(--role-surface-subtle), var(--role-surface-subtle-dark));
115
119
  --w-surface-muted: light-dark(var(--role-surface-muted), var(--role-surface-muted-dark));
116
120
  --w-surface-inset: light-dark(var(--role-surface-inset), var(--role-surface-inset-dark));
117
121
  --w-overlay: light-dark(var(--role-overlay), var(--role-overlay-dark));
@@ -1,6 +1,10 @@
1
- /* Multiline WInput (`textarea`): one `.line` per line, with a sticky line number and the active line highlighted. */
1
+ /*
2
+ * Numbered lines: one `.line` per line, wrapping its text in a `div`, with a sticky line number. Used by the multiline
3
+ * WInput (`w-textarea`) and by markdown code blocks. The active line (`line-active`) is highlighted, and so is the
4
+ * hovered one in a read-only textarea (`group/field`) or a markdown code block.
5
+ */
2
6
  @layer components {
3
- .w-textarea {
7
+ :is(.w-textarea, .w-markdown pre code) {
4
8
  counter-reset: w-textarea-lines;
5
9
  display: grid;
6
10
  grid-template-columns: auto 1fr;
@@ -8,7 +12,7 @@
8
12
  background: inherit;
9
13
  }
10
14
 
11
- .w-textarea .line {
15
+ :is(.w-textarea, .w-markdown pre code) .line {
12
16
  counter-increment: w-textarea-lines;
13
17
  display: grid;
14
18
  grid-template-columns: subgrid;
@@ -16,7 +20,7 @@
16
20
  background: inherit;
17
21
  }
18
22
 
19
- .w-textarea .line::before {
23
+ :is(.w-textarea, .w-markdown pre code) .line::before {
20
24
  content: counter(w-textarea-lines);
21
25
  position: sticky;
22
26
  left: 0;
@@ -25,41 +29,25 @@
25
29
  padding-right: --spacing(2);
26
30
  text-align: end;
27
31
  font-weight: 300;
28
- color: var(--color-gray-400);
32
+ color: light-dark(var(--color-gray-400), var(--color-gray-500));
29
33
  background-color: inherit;
30
34
  text-security: none;
31
35
  -webkit-text-security: none;
32
36
  }
33
37
 
34
- .w-textarea .line > div {
38
+ :is(.w-textarea, .w-markdown pre code) .line > div {
35
39
  padding-right: var(--w-option-padding);
36
40
  }
37
41
 
38
- .w-textarea .line > div > * {
42
+ :is(.w-textarea, .w-markdown pre code) .line > div > * {
39
43
  vertical-align: top;
40
44
  }
41
45
 
42
- .w-textarea .line.line-active > div,
43
- .w-textarea.group\/field .line:hover > div {
44
- background-color: color-mix(in oklab, var(--color-primary) 10%, transparent);
46
+ :is(.w-textarea .line.line-active, .w-textarea.group\/field .line:hover, .w-markdown:not(.w-report) pre code .line:hover) > div {
47
+ background-color: color-mix(in oklab, var(--w-primary) 10%, transparent);
45
48
  }
46
49
 
47
- .w-textarea .line.line-active::before,
48
- .w-textarea.group\/field .line:hover::before {
49
- color: var(--color-black-default);
50
- }
51
-
52
- .dark .w-textarea:not(:is(.light *)) .line::before {
53
- color: var(--color-gray-500);
54
- }
55
-
56
- .dark .w-textarea:not(:is(.light *)) .line.line-active > div,
57
- .dark .w-textarea.group\/field:not(:is(.light *)) .line:hover > div {
58
- background-color: color-mix(in oklab, var(--color-primary-dark) 10%, transparent);
59
- }
60
-
61
- .dark .w-textarea:not(:is(.light *)) .line.line-active::before,
62
- .dark .w-textarea.group\/field:not(:is(.light *)) .line:hover::before {
63
- color: var(--color-default);
50
+ :is(.w-textarea .line.line-active, .w-textarea.group\/field .line:hover, .w-markdown:not(.w-report) pre code .line:hover)::before {
51
+ color: var(--w-text-accent);
64
52
  }
65
53
  }
@@ -14,8 +14,8 @@
14
14
  */
15
15
  --color-primary: oklch(55% 0.17 286.8);
16
16
  --color-primary-dark: var(--color-primary);
17
- --color-primary-light: color-mix(in oklab, var(--color-primary) 10%, var(--color-default));
18
- --color-primary-darkest: color-mix(in oklab, var(--color-primary-dark) 20%, var(--color-default-dark));
17
+ --color-primary-light: color-mix(in oklab, var(--color-primary) 7%, var(--color-default));
18
+ --color-primary-darkest: color-mix(in oklab, var(--color-primary-dark) 10%, var(--color-default-dark));
19
19
 
20
20
  --color-black-default: #333333;
21
21
  --color-black-light: #4f4f4f;
@@ -0,0 +1,8 @@
1
+ /*
2
+ * Styles for rendered markdown in `.w-markdown`. Import after `base.css`:
3
+ *
4
+ * @import "eco-vue-js/tailwind-base/markdown.css";
5
+ * @import "eco-vue-js/tailwind-base/css/markdown/blocks.css"; // GitBook blocks: hints, colored text, details…
6
+ */
7
+ @import "./css/markdown/prose.css";
8
+ @import "./css/markdown/code.css";