@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 +14 -0
- package/dist/Button.d.ts +1 -1
- package/dist/ProgressBar.css +82 -0
- package/dist/ProgressBar.d.ts +23 -0
- package/dist/ProgressBar.js +31 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/styles.css +97 -0
- package/package.json +12 -7
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
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.
|
|
4
|
-
"description": "Shared brand-visible React components (Button, Badge, Card) for vvp_link_shortener and
|
|
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
|
+
}
|