@volksverpetzer/ui-web 0.1.0 → 0.3.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.
package/dist/Button.css CHANGED
@@ -62,3 +62,17 @@
62
62
  .vvp-ui-btn--ghost:hover:not(:disabled) {
63
63
  background: var(--vvp-surface, #e2f0f5);
64
64
  }
65
+
66
+ /*
67
+ * For donation/campaign CTAs, where the pink brand accent (not primary
68
+ * blue) is the call-to-action color — e.g. vvp_divi5_extensions's
69
+ * campaign-donate module and the crowdfunding site's donate button.
70
+ */
71
+ .vvp-ui-btn--accent {
72
+ background: var(--vvp-accent, #db2685);
73
+ color: var(--vvp-on-primary, #fff);
74
+ }
75
+
76
+ .vvp-ui-btn--accent:hover:not(:disabled) {
77
+ background: color-mix(in srgb, var(--vvp-accent, #db2685) 85%, black);
78
+ }
package/dist/Button.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ButtonHTMLAttributes, ReactNode } from "react";
2
2
  import "./Button.css";
3
- export type ButtonVariant = "primary" | "secondary" | "ghost";
3
+ export type ButtonVariant = "primary" | "secondary" | "ghost" | "accent";
4
4
  export type ButtonSize = "sm" | "md" | "lg";
5
5
  export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
6
6
  variant?: ButtonVariant;
@@ -0,0 +1,82 @@
1
+ .vvp-ui-progress {
2
+ width: 100%;
3
+ text-align: center;
4
+ }
5
+
6
+ .vvp-ui-progress__amounts {
7
+ display: flex;
8
+ align-items: baseline;
9
+ justify-content: center;
10
+ gap: var(--vvp-spacing-sm, 8px);
11
+ margin-bottom: var(--vvp-spacing-sm, 8px);
12
+ flex-wrap: wrap;
13
+ }
14
+
15
+ .vvp-ui-progress__total {
16
+ font-weight: 700;
17
+ font-size: var(--vvp-font-size-xxl, 24px);
18
+ line-height: 1.2;
19
+ }
20
+
21
+ .vvp-ui-progress__goal {
22
+ font-size: var(--vvp-font-size-sm, 14px);
23
+ color: var(--vvp-text-muted, #666);
24
+ }
25
+
26
+ .vvp-ui-progress__track-row {
27
+ display: flex;
28
+ flex-wrap: nowrap;
29
+ width: 100%;
30
+ gap: 0;
31
+ }
32
+
33
+ .vvp-ui-progress__step {
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: var(--vvp-spacing-xs, 4px);
37
+ min-width: 0;
38
+ }
39
+
40
+ .vvp-ui-progress__track {
41
+ width: 100%;
42
+ height: 24px;
43
+ background: var(--vvp-surface-disabled, #ddd);
44
+ border: 1px solid var(--vvp-surface-input, #badde8);
45
+ overflow: hidden;
46
+ position: relative;
47
+ }
48
+
49
+ .vvp-ui-progress__step:first-child .vvp-ui-progress__track {
50
+ border-top-left-radius: var(--vvp-radius-full, 9999px);
51
+ border-bottom-left-radius: var(--vvp-radius-full, 9999px);
52
+ }
53
+
54
+ .vvp-ui-progress__step:last-child .vvp-ui-progress__track {
55
+ border-top-right-radius: var(--vvp-radius-full, 9999px);
56
+ border-bottom-right-radius: var(--vvp-radius-full, 9999px);
57
+ }
58
+
59
+ .vvp-ui-progress__step + .vvp-ui-progress__step .vvp-ui-progress__track {
60
+ border-left: 0;
61
+ }
62
+
63
+ .vvp-ui-progress__fill {
64
+ height: 100%;
65
+ border-radius: inherit;
66
+ background: linear-gradient(120deg, var(--vvp-accent, #db2685), color-mix(in srgb, var(--vvp-accent, #db2685) 85%, black));
67
+ transition: width 300ms ease-out;
68
+ }
69
+
70
+ .vvp-ui-progress__step-label {
71
+ display: flex;
72
+ flex-direction: column;
73
+ align-items: flex-end;
74
+ gap: 2px;
75
+ font-size: var(--vvp-font-size-sm, 14px);
76
+ color: var(--vvp-text-muted, #666);
77
+ text-align: right;
78
+ }
79
+
80
+ .vvp-ui-progress__step-label strong {
81
+ color: var(--vvp-text, #111);
82
+ }
@@ -0,0 +1,23 @@
1
+ import type { HTMLAttributes } from "react";
2
+ import "./ProgressBar.css";
3
+ export interface ProgressBarMilestone {
4
+ value: number;
5
+ label: string;
6
+ }
7
+ export interface ProgressBarProps extends HTMLAttributes<HTMLDivElement> {
8
+ total: number;
9
+ goal: number;
10
+ /**
11
+ * Stretch goals to render as separate segments, e.g. for a campaign with
12
+ * multiple funding tiers. Omit (or pass a single entry) for a plain bar
13
+ * with one segment running from 0 to `goal` — the common case.
14
+ */
15
+ milestones?: ProgressBarMilestone[];
16
+ }
17
+ /**
18
+ * Campaign donation progress bar — one segment by default (0 to `goal`), or
19
+ * multiple stacked segments when `milestones` has more than one entry.
20
+ * Styled off the `--vvp-*` custom properties emitted by
21
+ * `@volksverpetzer/design-tokens`, same as the other components here.
22
+ */
23
+ export declare function ProgressBar({ total, goal, milestones, className, ...rest }: ProgressBarProps): import("react").JSX.Element;
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "./ProgressBar.css";
3
+ const formatEuro = (value) => value.toLocaleString("de-DE", { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + " €";
4
+ /**
5
+ * Campaign donation progress bar — one segment by default (0 to `goal`), or
6
+ * multiple stacked segments when `milestones` has more than one entry.
7
+ * Styled off the `--vvp-*` custom properties emitted by
8
+ * `@volksverpetzer/design-tokens`, same as the other components here.
9
+ */
10
+ export function ProgressBar({ total, goal, milestones, className, ...rest }) {
11
+ const steps = milestones && milestones.length > 1 ? [...milestones].sort((a, b) => a.value - b.value) : [{ value: goal, label: "" }];
12
+ const isSingleStep = steps.length === 1;
13
+ const target = steps[steps.length - 1].value;
14
+ const segments = steps.map((step, index) => {
15
+ const start = index === 0 ? 0 : steps[index - 1].value;
16
+ const range = step.value - start;
17
+ const filled = Math.min(Math.max(total - start, 0), range);
18
+ const percent = range > 0 ? Math.min(100, (filled / range) * 100) : 0;
19
+ const width = target > 0 ? (range / target) * 100 : 0;
20
+ return { ...step, start, range, filled, percent, width };
21
+ });
22
+ const classes = ["vvp-ui-progress", className].filter(Boolean).join(" ");
23
+ return (_jsxs("div", { className: classes, ...rest, children: [isSingleStep ? (_jsxs("div", { className: "vvp-ui-progress__amounts", children: [_jsx("span", { className: "vvp-ui-progress__total", children: formatEuro(total) }), _jsxs("span", { className: "vvp-ui-progress__goal", children: [" von ", formatEuro(goal)] })] })) : null, _jsx("div", { className: "vvp-ui-progress__track-row", role: "group", "aria-label": "Spendenfortschritt", children: segments.map((segment, index) => {
24
+ const valueNow = Math.min(Math.max(total, segment.start), segment.value);
25
+ return (_jsxs("div", { className: "vvp-ui-progress__step", style: { flexBasis: `${segment.width}%`, flexGrow: segment.width, flexShrink: 0 }, children: [_jsx("div", { className: "vvp-ui-progress__track", role: "progressbar", "aria-valuemin": segment.start, "aria-valuemax": segment.value, "aria-valuenow": valueNow, "aria-valuetext": isSingleStep
26
+ ? `${formatEuro(total)} von ${formatEuro(goal)}`
27
+ : `${formatEuro(total)} insgesamt gesammelt, ${formatEuro(segment.filled)} von ${formatEuro(segment.range)} für „${segment.label}“`, "aria-label": isSingleStep
28
+ ? `${formatEuro(total)} von ${formatEuro(goal)} gesammelt`
29
+ : `${segment.label} (${formatEuro(segment.value)})`, children: _jsx("div", { className: "vvp-ui-progress__fill", style: { width: `${segment.percent}%` } }) }), !isSingleStep ? (_jsxs("div", { className: "vvp-ui-progress__step-label", children: [_jsx("strong", { children: segment.label }), _jsx("span", { children: formatEuro(segment.value) })] })) : null] }, `${segment.value}-${index}`));
30
+ }) })] }));
31
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { Button, type ButtonProps, type ButtonVariant, type ButtonSize } from "./Button";
2
2
  export { Badge, type BadgeProps, type BadgeVariant } from "./Badge";
3
3
  export { Card, type CardProps } from "./Card";
4
+ export { ProgressBar, type ProgressBarProps, type ProgressBarMilestone } from "./ProgressBar";
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { Button } from "./Button";
2
2
  export { Badge } from "./Badge";
3
3
  export { Card } from "./Card";
4
+ export { ProgressBar } from "./ProgressBar";
package/dist/styles.css CHANGED
@@ -93,6 +93,20 @@
93
93
  background: var(--vvp-surface, #e2f0f5);
94
94
  }
95
95
 
96
+ /*
97
+ * For donation/campaign CTAs, where the pink brand accent (not primary
98
+ * blue) is the call-to-action color — e.g. vvp_divi5_extensions's
99
+ * campaign-donate module and the crowdfunding site's donate button.
100
+ */
101
+ .vvp-ui-btn--accent {
102
+ background: var(--vvp-accent, #db2685);
103
+ color: var(--vvp-on-primary, #fff);
104
+ }
105
+
106
+ .vvp-ui-btn--accent:hover:not(:disabled) {
107
+ background: color-mix(in srgb, var(--vvp-accent, #db2685) 85%, black);
108
+ }
109
+
96
110
  .vvp-ui-card {
97
111
  background: var(--vvp-background, #fff);
98
112
  border-radius: var(--vvp-radius-md, 12px);
@@ -103,3 +117,86 @@
103
117
  border: 1px solid var(--vvp-surface-input, #badde8);
104
118
  }
105
119
 
120
+ .vvp-ui-progress {
121
+ width: 100%;
122
+ text-align: center;
123
+ }
124
+
125
+ .vvp-ui-progress__amounts {
126
+ display: flex;
127
+ align-items: baseline;
128
+ justify-content: center;
129
+ gap: var(--vvp-spacing-sm, 8px);
130
+ margin-bottom: var(--vvp-spacing-sm, 8px);
131
+ flex-wrap: wrap;
132
+ }
133
+
134
+ .vvp-ui-progress__total {
135
+ font-weight: 700;
136
+ font-size: var(--vvp-font-size-xxl, 24px);
137
+ line-height: 1.2;
138
+ }
139
+
140
+ .vvp-ui-progress__goal {
141
+ font-size: var(--vvp-font-size-sm, 14px);
142
+ color: var(--vvp-text-muted, #666);
143
+ }
144
+
145
+ .vvp-ui-progress__track-row {
146
+ display: flex;
147
+ flex-wrap: nowrap;
148
+ width: 100%;
149
+ gap: 0;
150
+ }
151
+
152
+ .vvp-ui-progress__step {
153
+ display: flex;
154
+ flex-direction: column;
155
+ gap: var(--vvp-spacing-xs, 4px);
156
+ min-width: 0;
157
+ }
158
+
159
+ .vvp-ui-progress__track {
160
+ width: 100%;
161
+ height: 24px;
162
+ background: var(--vvp-surface-disabled, #ddd);
163
+ border: 1px solid var(--vvp-surface-input, #badde8);
164
+ overflow: hidden;
165
+ position: relative;
166
+ }
167
+
168
+ .vvp-ui-progress__step:first-child .vvp-ui-progress__track {
169
+ border-top-left-radius: var(--vvp-radius-full, 9999px);
170
+ border-bottom-left-radius: var(--vvp-radius-full, 9999px);
171
+ }
172
+
173
+ .vvp-ui-progress__step:last-child .vvp-ui-progress__track {
174
+ border-top-right-radius: var(--vvp-radius-full, 9999px);
175
+ border-bottom-right-radius: var(--vvp-radius-full, 9999px);
176
+ }
177
+
178
+ .vvp-ui-progress__step + .vvp-ui-progress__step .vvp-ui-progress__track {
179
+ border-left: 0;
180
+ }
181
+
182
+ .vvp-ui-progress__fill {
183
+ height: 100%;
184
+ border-radius: inherit;
185
+ background: linear-gradient(120deg, var(--vvp-accent, #db2685), color-mix(in srgb, var(--vvp-accent, #db2685) 85%, black));
186
+ transition: width 300ms ease-out;
187
+ }
188
+
189
+ .vvp-ui-progress__step-label {
190
+ display: flex;
191
+ flex-direction: column;
192
+ align-items: flex-end;
193
+ gap: 2px;
194
+ font-size: var(--vvp-font-size-sm, 14px);
195
+ color: var(--vvp-text-muted, #666);
196
+ text-align: right;
197
+ }
198
+
199
+ .vvp-ui-progress__step-label strong {
200
+ color: var(--vvp-text, #111);
201
+ }
202
+
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@volksverpetzer/ui-web",
3
- "version": "0.1.0",
4
- "description": "Shared brand-visible React components (Button, Badge, Card) for vvp_link_shortener and vvp_divi5_extensions. Plain, hand-scoped CSS (vvp-ui-* class prefix) consuming the --vvp-* custom properties emitted by @volksverpetzer/design-tokens — no Tailwind classes, so it drops into a Tailwind app and Divi's WordPress-embedded CSS alike.",
3
+ "version": "0.3.0",
4
+ "description": "Shared brand-visible React components (Button, Badge, Card) for vvp_link_shortener, vvp_divi5_extensions, and crowdfunding. Plain, hand-scoped CSS (vvp-ui-* class prefix) consuming the --vvp-* custom properties emitted by @volksverpetzer/design-tokens — no Tailwind classes, so it drops into a Tailwind app and Divi's WordPress-embedded CSS alike.",
5
5
  "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Volksverpetzer/vvp_design_system.git",
9
+ "directory": "packages/ui-web"
10
+ },
6
11
  "publishConfig": {
7
12
  "access": "public",
8
13
  "registry": "https://registry.npmjs.org"
@@ -20,13 +25,13 @@
20
25
  "peerDependencies": {
21
26
  "react": ">=19"
22
27
  },
23
- "scripts": {
24
- "build": "tsc -p tsconfig.json && node scripts/bundle-css.mjs",
25
- "check:ts": "tsc --noEmit -p tsconfig.json"
26
- },
27
28
  "devDependencies": {
28
29
  "@types/react": "^19.2.18",
29
30
  "react": "^19.2.3",
30
31
  "typescript": "^5.9.3"
32
+ },
33
+ "scripts": {
34
+ "build": "tsc -p tsconfig.json && node scripts/bundle-css.mjs",
35
+ "check:ts": "tsc --noEmit -p tsconfig.json"
31
36
  }
32
- }
37
+ }