@mostrom/app-shell 0.1.1 → 0.1.2
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/README.md +22 -47
- package/bun.lock +5 -3
- package/package.json +3 -3
- package/scripts/publish-npm.sh +71 -14
- package/src/components/sectioned-list-board/board-card-content.tsx +3 -3
- package/src/components/sectioned-list-table/table-cell-content.tsx +1 -1
- package/src/components/ui/badge.tsx +59 -0
- package/src/components/ui/button.tsx +7 -1
- package/src/components/ui/index.ts +2 -0
- package/src/components/ui/space-between.tsx +59 -0
- package/src/vite.js +7 -7
- package/bin/init.js +0 -269
package/README.md
CHANGED
|
@@ -14,69 +14,50 @@ From `platform/shared/packages/app-shell`:
|
|
|
14
14
|
Default scope is `@mostrom` (override with `--scope` if needed).
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
# Dry run
|
|
18
|
-
npm run publish:npm:dry-run
|
|
19
|
-
# or: sh scripts/publish-npm.sh --
|
|
17
|
+
# Dry run (auto-increment patch version)
|
|
18
|
+
npm run publish:npm:dry-run
|
|
19
|
+
# or: sh scripts/publish-npm.sh --dry-run
|
|
20
20
|
|
|
21
|
-
# Publish to latest
|
|
21
|
+
# Publish to latest (auto-increment patch version)
|
|
22
|
+
npm run publish:npm
|
|
23
|
+
# or: sh scripts/publish-npm.sh
|
|
24
|
+
|
|
25
|
+
# First run or explicit override
|
|
22
26
|
npm run publish:npm -- --version 0.1.0
|
|
23
27
|
# or: sh scripts/publish-npm.sh --version 0.1.0
|
|
24
28
|
|
|
25
29
|
# Publish to custom tag
|
|
26
|
-
npm run publish:npm -- --
|
|
27
|
-
# or: sh scripts/publish-npm.sh --
|
|
30
|
+
npm run publish:npm -- --tag next
|
|
31
|
+
# or: sh scripts/publish-npm.sh --tag next
|
|
28
32
|
```
|
|
29
33
|
|
|
30
|
-
The script reads `NODE_AUTH_TOKEN` from environment variables, and also checks `app-shell/.env` for that key.
|
|
34
|
+
The script reads `NODE_AUTH_TOKEN` from environment variables, and also checks `app-shell/.env` for that key. It stores the last successful version in `scripts/.publish-version` and auto-increments patch versions on subsequent runs.
|
|
31
35
|
|
|
32
36
|
## Quick Start
|
|
33
37
|
|
|
34
|
-
###
|
|
35
|
-
|
|
36
|
-
Run the init script to configure a new app to use app-shell:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
# From your app's frontend directory, run the init script directly
|
|
40
|
-
node ../../../shared/packages/app-shell/bin/init.js
|
|
41
|
-
|
|
42
|
-
# Force overwrite existing files
|
|
43
|
-
node ../../../shared/packages/app-shell/bin/init.js --force
|
|
38
|
+
### Setup (No Init Script)
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
./node_modules/.bin/app-shell-init
|
|
47
|
-
```
|
|
40
|
+
App setup is now file-based and does not require running an init command.
|
|
48
41
|
|
|
49
|
-
|
|
42
|
+
Required app files:
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- `
|
|
54
|
-
- `
|
|
55
|
-
- `
|
|
56
|
-
- `app/lib/utils.ts` - Utility functions (cn, getBasePathHref)
|
|
57
|
-
|
|
58
|
-
### When to Run Init
|
|
59
|
-
|
|
60
|
-
| Scenario | Run Init? |
|
|
61
|
-
| ------------------------------------------- | ---------------------------------------------------- |
|
|
62
|
-
| Setting up a new app | Yes |
|
|
63
|
-
| CSS changes in app-shell | No - changes are picked up automatically |
|
|
64
|
-
| Adding new shadcn components | No - use `npx shadcn@latest add <component>` |
|
|
65
|
-
| Tailwind not scanning app-shell classes | Yes, with `--force` to regenerate tailwind.config.ts |
|
|
66
|
-
| Upgrading app-shell with new required files | Yes, with `--force` |
|
|
44
|
+
- `app/tailwind.css`
|
|
45
|
+
- `tailwind.config.ts`
|
|
46
|
+
- `components.json`
|
|
47
|
+
- `app/lib/utils.ts`
|
|
48
|
+
- `vite.config.ts` using `getSharedViteConfig()` from `@platform/app-shell/vite`
|
|
67
49
|
|
|
68
50
|
### Troubleshooting
|
|
69
51
|
|
|
70
52
|
**Styles not applying from app-shell:**
|
|
71
53
|
|
|
72
|
-
1. Ensure `tailwind.config.ts` includes
|
|
54
|
+
1. Ensure `tailwind.config.ts` includes app-shell content:
|
|
73
55
|
```ts
|
|
74
56
|
content: [
|
|
75
57
|
"./app/**/*.{ts,tsx,js,jsx}",
|
|
76
|
-
"
|
|
58
|
+
"./node_modules/@platform/app-shell/src/**/*.{ts,tsx}",
|
|
77
59
|
],
|
|
78
60
|
```
|
|
79
|
-
2. Run `node ../../../shared/packages/app-shell/bin/init.js --force` to regenerate config files
|
|
80
61
|
|
|
81
62
|
**Conflicting CSS (wrong colors, broken layout):**
|
|
82
63
|
|
|
@@ -158,13 +139,7 @@ The App Shell builds the **All services** menu and global search suggestions fro
|
|
|
158
139
|
`@mostrom/service-catalog`. Until we move to a monorepo workspace setup, each
|
|
159
140
|
app should explicitly depend on this package to avoid module resolution issues.
|
|
160
141
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
```json
|
|
164
|
-
{
|
|
165
|
-
"@mostrom/service-catalog": "file:../../../shared/packages/service-catalog"
|
|
166
|
-
}
|
|
167
|
-
```
|
|
142
|
+
When consuming published packages, install `@platform/service-catalog` as an npm alias to `@mostrom/service-catalog`.
|
|
168
143
|
|
|
169
144
|
## Notes
|
|
170
145
|
|
package/bun.lock
CHANGED
|
@@ -35,9 +35,11 @@
|
|
|
35
35
|
"vaul": "^1.1.2",
|
|
36
36
|
"zod": "^4.3.6",
|
|
37
37
|
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/react": "19.2.14",
|
|
40
|
+
"@types/react-dom": "19.2.3",
|
|
41
|
+
},
|
|
38
42
|
"peerDependencies": {
|
|
39
|
-
"@types/react": "^19.0.0",
|
|
40
|
-
"@types/react-dom": "^19.0.0",
|
|
41
43
|
"react": "^19.0.0",
|
|
42
44
|
"react-dom": "^19.0.0",
|
|
43
45
|
},
|
|
@@ -242,7 +244,7 @@
|
|
|
242
244
|
|
|
243
245
|
"@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
|
|
244
246
|
|
|
245
|
-
"@types/react": ["@types/react@19.2.
|
|
247
|
+
"@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
|
|
246
248
|
|
|
247
249
|
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
|
248
250
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostrom/app-shell",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"@dnd-kit/utilities": "^3.2.2",
|
|
36
36
|
"@floating-ui/dom": "^1.7.5",
|
|
37
37
|
"@hookform/resolvers": "^5.2.2",
|
|
38
|
+
"@platform/service-catalog": "npm:@mostrom/service-catalog@^0.1.2",
|
|
38
39
|
"@radix-ui/react-dropdown-menu": "^2.1.4",
|
|
39
40
|
"@tanstack/react-table": "^8.21.3",
|
|
40
41
|
"class-variance-authority": "^0.7.1",
|
|
@@ -53,8 +54,7 @@
|
|
|
53
54
|
"tailwind-merge": "^3.4.0",
|
|
54
55
|
"tw-animate-css": "^1.4.0",
|
|
55
56
|
"vaul": "^1.1.2",
|
|
56
|
-
"zod": "^4.3.6"
|
|
57
|
-
"@mostrom/service-catalog": "^0.1.1"
|
|
57
|
+
"zod": "^4.3.6"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
60
|
"@types/react": "19.2.14",
|
package/scripts/publish-npm.sh
CHANGED
|
@@ -4,14 +4,15 @@ set -eu
|
|
|
4
4
|
usage() {
|
|
5
5
|
cat <<USAGE
|
|
6
6
|
Usage:
|
|
7
|
-
./scripts/publish-npm.sh --version <version> [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
8
|
-
./scripts/publish-npm.sh <version> [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
7
|
+
./scripts/publish-npm.sh [--version <version>] [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
8
|
+
./scripts/publish-npm.sh [<version>] [--scope <scope>] [--tag <tag>] [--otp <code>] [--dry-run]
|
|
9
9
|
|
|
10
10
|
Examples:
|
|
11
|
+
./scripts/publish-npm.sh
|
|
11
12
|
./scripts/publish-npm.sh 0.1.0
|
|
12
13
|
./scripts/publish-npm.sh --version 0.1.0 --scope @mostrom --tag next
|
|
13
14
|
./scripts/publish-npm.sh --version 0.1.0 --scope mostrom --otp 123456
|
|
14
|
-
./scripts/publish-npm.sh --
|
|
15
|
+
./scripts/publish-npm.sh --dry-run
|
|
15
16
|
USAGE
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -19,6 +20,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
19
20
|
APP_SHELL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
20
21
|
PACKAGES_DIR="$(cd "${APP_SHELL_DIR}/.." && pwd)"
|
|
21
22
|
SERVICE_CATALOG_DIR="${PACKAGES_DIR}/service-catalog"
|
|
23
|
+
VERSION_STATE_FILE="${SCRIPT_DIR}/.publish-version"
|
|
22
24
|
|
|
23
25
|
VERSION=""
|
|
24
26
|
SCOPE="@mostrom"
|
|
@@ -69,12 +71,6 @@ while [ "$#" -gt 0 ]; do
|
|
|
69
71
|
esac
|
|
70
72
|
done
|
|
71
73
|
|
|
72
|
-
if [ -z "$VERSION" ]; then
|
|
73
|
-
echo "Error: version is required." >&2
|
|
74
|
-
usage
|
|
75
|
-
exit 1
|
|
76
|
-
fi
|
|
77
|
-
|
|
78
74
|
case "$SCOPE" in
|
|
79
75
|
@*) ;;
|
|
80
76
|
*) SCOPE="@$SCOPE" ;;
|
|
@@ -89,6 +85,54 @@ fi
|
|
|
89
85
|
SERVICE_CATALOG_PACKAGE_NAME="${SCOPE}/service-catalog"
|
|
90
86
|
APP_SHELL_PACKAGE_NAME="${SCOPE}/app-shell"
|
|
91
87
|
|
|
88
|
+
bump_patch_version() {
|
|
89
|
+
current_version="$1"
|
|
90
|
+
CURRENT_VERSION="$current_version" node - <<'NODE'
|
|
91
|
+
const value = process.env.CURRENT_VERSION;
|
|
92
|
+
if (!/^\d+\.\d+\.\d+$/.test(value || "")) {
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const [major, minor, patch] = value.split('.').map(Number);
|
|
96
|
+
process.stdout.write(`${major}.${minor}.${patch + 1}`);
|
|
97
|
+
NODE
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
infer_next_version() {
|
|
101
|
+
if [ -f "$VERSION_STATE_FILE" ]; then
|
|
102
|
+
last_version="$(tr -d '[:space:]' < "$VERSION_STATE_FILE")"
|
|
103
|
+
if [ -z "$last_version" ]; then
|
|
104
|
+
echo "Error: $VERSION_STATE_FILE is empty. Pass --version explicitly once." >&2
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
next_version="$(bump_patch_version "$last_version" || true)"
|
|
108
|
+
if [ -z "$next_version" ]; then
|
|
109
|
+
echo "Error: invalid version in $VERSION_STATE_FILE ($last_version). Pass --version explicitly once." >&2
|
|
110
|
+
exit 1
|
|
111
|
+
fi
|
|
112
|
+
echo "$next_version"
|
|
113
|
+
return 0
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
latest_registry_version="$(npm view "$SERVICE_CATALOG_PACKAGE_NAME" version 2>/dev/null || true)"
|
|
117
|
+
if [ -n "$latest_registry_version" ]; then
|
|
118
|
+
next_version="$(bump_patch_version "$latest_registry_version" || true)"
|
|
119
|
+
if [ -z "$next_version" ]; then
|
|
120
|
+
echo "Error: failed to parse latest registry version ($latest_registry_version). Pass --version explicitly." >&2
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
echo "$next_version"
|
|
124
|
+
return 0
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
echo "Error: Could not infer next version. Pass --version explicitly once (for example: --version 0.1.0)." >&2
|
|
128
|
+
exit 1
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if [ -z "$VERSION" ]; then
|
|
132
|
+
VERSION="$(infer_next_version)"
|
|
133
|
+
echo "==> Auto-incremented version: ${VERSION}"
|
|
134
|
+
fi
|
|
135
|
+
|
|
92
136
|
TMP_DIR="$(mktemp -d)"
|
|
93
137
|
cleanup() {
|
|
94
138
|
rm -rf "$TMP_DIR"
|
|
@@ -126,6 +170,7 @@ copy_pkg() {
|
|
|
126
170
|
--exclude .env \
|
|
127
171
|
--exclude test-results \
|
|
128
172
|
--exclude .DS_Store \
|
|
173
|
+
--exclude scripts/.publish-version \
|
|
129
174
|
"$from_dir/" "$to_dir/"
|
|
130
175
|
}
|
|
131
176
|
|
|
@@ -135,12 +180,14 @@ rewrite_manifest() {
|
|
|
135
180
|
package_name="$3"
|
|
136
181
|
service_catalog_package="${4:-}"
|
|
137
182
|
service_catalog_range="${5:-}"
|
|
183
|
+
service_catalog_alias="${6:-}"
|
|
138
184
|
|
|
139
185
|
MANIFEST_PATH="$manifest_path" \
|
|
140
186
|
PACKAGE_VERSION="$package_version" \
|
|
141
187
|
PACKAGE_NAME="$package_name" \
|
|
142
188
|
SERVICE_CATALOG_PACKAGE="$service_catalog_package" \
|
|
143
189
|
SERVICE_CATALOG_RANGE="$service_catalog_range" \
|
|
190
|
+
SERVICE_CATALOG_ALIAS="$service_catalog_alias" \
|
|
144
191
|
node - <<'NODE'
|
|
145
192
|
const fs = require('fs');
|
|
146
193
|
const p = process.env.MANIFEST_PATH;
|
|
@@ -148,15 +195,18 @@ const version = process.env.PACKAGE_VERSION;
|
|
|
148
195
|
const packageName = process.env.PACKAGE_NAME;
|
|
149
196
|
const serviceCatalogPackage = process.env.SERVICE_CATALOG_PACKAGE;
|
|
150
197
|
const serviceCatalogRange = process.env.SERVICE_CATALOG_RANGE;
|
|
198
|
+
const serviceCatalogAlias = process.env.SERVICE_CATALOG_ALIAS;
|
|
151
199
|
const pkg = JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
152
200
|
pkg.name = packageName;
|
|
153
201
|
pkg.version = version;
|
|
154
202
|
pkg.private = false;
|
|
155
203
|
pkg.publishConfig = { ...(pkg.publishConfig || {}), access: 'public' };
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
204
|
+
if (serviceCatalogAlias) {
|
|
205
|
+
pkg.dependencies = { ...(pkg.dependencies || {}), ['@platform/service-catalog']: serviceCatalogAlias };
|
|
206
|
+
if (serviceCatalogPackage && pkg.dependencies && pkg.dependencies[serviceCatalogPackage]) {
|
|
207
|
+
delete pkg.dependencies[serviceCatalogPackage];
|
|
208
|
+
}
|
|
209
|
+
} else if (serviceCatalogPackage && serviceCatalogRange) {
|
|
160
210
|
pkg.dependencies = { ...(pkg.dependencies || {}), [serviceCatalogPackage]: serviceCatalogRange };
|
|
161
211
|
}
|
|
162
212
|
fs.writeFileSync(p, JSON.stringify(pkg, null, 2) + '\n');
|
|
@@ -171,7 +221,7 @@ copy_pkg "$SERVICE_CATALOG_DIR" "$SERVICE_TMP_DIR"
|
|
|
171
221
|
copy_pkg "$APP_SHELL_DIR" "$APP_SHELL_TMP_DIR"
|
|
172
222
|
|
|
173
223
|
rewrite_manifest "${SERVICE_TMP_DIR}/package.json" "$VERSION" "$SERVICE_CATALOG_PACKAGE_NAME"
|
|
174
|
-
rewrite_manifest "${APP_SHELL_TMP_DIR}/package.json" "$VERSION" "$APP_SHELL_PACKAGE_NAME" "$SERVICE_CATALOG_PACKAGE_NAME" "^${VERSION}"
|
|
224
|
+
rewrite_manifest "${APP_SHELL_TMP_DIR}/package.json" "$VERSION" "$APP_SHELL_PACKAGE_NAME" "$SERVICE_CATALOG_PACKAGE_NAME" "^${VERSION}" "npm:${SERVICE_CATALOG_PACKAGE_NAME}@^${VERSION}"
|
|
175
225
|
|
|
176
226
|
publish_pkg() {
|
|
177
227
|
pkg_dir="$1"
|
|
@@ -196,7 +246,14 @@ publish_pkg() {
|
|
|
196
246
|
publish_pkg "$SERVICE_TMP_DIR" "$SERVICE_CATALOG_PACKAGE_NAME"
|
|
197
247
|
publish_pkg "$APP_SHELL_TMP_DIR" "$APP_SHELL_PACKAGE_NAME"
|
|
198
248
|
|
|
249
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
250
|
+
printf "%s\n" "$VERSION" > "$VERSION_STATE_FILE"
|
|
251
|
+
fi
|
|
252
|
+
|
|
199
253
|
echo "==> Done"
|
|
200
254
|
echo "Published version: ${VERSION}"
|
|
201
255
|
echo "Scope: ${SCOPE}"
|
|
202
256
|
echo "Tag: ${TAG}"
|
|
257
|
+
if [ "$DRY_RUN" -eq 0 ]; then
|
|
258
|
+
echo "Version state file: ${VERSION_STATE_FILE}"
|
|
259
|
+
fi
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as Popover from "@radix-ui/react-popover";
|
|
3
|
-
import Badge from "
|
|
4
|
-
import Button from "
|
|
5
|
-
import SpaceBetween from "
|
|
3
|
+
import { Badge } from "../ui/badge";
|
|
4
|
+
import { Button } from "../ui/button";
|
|
5
|
+
import { SpaceBetween } from "../ui/space-between";
|
|
6
6
|
import { format, isToday, isTomorrow, isValid, parseISO } from "date-fns";
|
|
7
7
|
import {
|
|
8
8
|
DateSelector,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import Badge from "
|
|
2
|
+
import { Badge } from "../ui/badge";
|
|
3
3
|
import type { Assignee, ColumnDefinition, TableBadgeColor } from "./types";
|
|
4
4
|
import { AssigneeSelector } from "@/components/ui/assignee-selector";
|
|
5
5
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
import { Slot } from "radix-ui"
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center rounded-full border border-transparent px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
|
|
13
|
+
secondary:
|
|
14
|
+
"bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
|
|
15
|
+
destructive:
|
|
16
|
+
"bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
17
|
+
outline:
|
|
18
|
+
"border-border text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
19
|
+
ghost: "[a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
|
|
20
|
+
link: "text-primary underline-offset-4 [a&]:hover:underline",
|
|
21
|
+
},
|
|
22
|
+
// Color variants for Cloudscape compatibility
|
|
23
|
+
color: {
|
|
24
|
+
blue: "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200",
|
|
25
|
+
green: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200",
|
|
26
|
+
grey: "bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200",
|
|
27
|
+
red: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: "default",
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
function Badge({
|
|
37
|
+
className,
|
|
38
|
+
variant,
|
|
39
|
+
color,
|
|
40
|
+
asChild = false,
|
|
41
|
+
...props
|
|
42
|
+
}: React.ComponentProps<"span"> &
|
|
43
|
+
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
|
44
|
+
const Comp = asChild ? Slot.Root : "span"
|
|
45
|
+
|
|
46
|
+
// If color is provided, use color variant; otherwise use variant (defaulting to "default")
|
|
47
|
+
const resolvedVariant = color ? undefined : (variant ?? "default")
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Comp
|
|
51
|
+
data-slot="badge"
|
|
52
|
+
data-variant={color ?? variant}
|
|
53
|
+
className={cn(badgeVariants({ variant: resolvedVariant, color }), className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { Badge, badgeVariants }
|
|
@@ -19,6 +19,10 @@ const buttonVariants = cva(
|
|
|
19
19
|
ghost:
|
|
20
20
|
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
21
21
|
link: "text-primary underline-offset-4 hover:underline",
|
|
22
|
+
// Cloudscape-compatible variants
|
|
23
|
+
primary: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
24
|
+
normal:
|
|
25
|
+
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
22
26
|
},
|
|
23
27
|
size: {
|
|
24
28
|
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
@@ -43,10 +47,12 @@ function Button({
|
|
|
43
47
|
variant = "default",
|
|
44
48
|
size = "default",
|
|
45
49
|
asChild = false,
|
|
50
|
+
fullWidth = false,
|
|
46
51
|
...props
|
|
47
52
|
}: React.ComponentProps<"button"> &
|
|
48
53
|
VariantProps<typeof buttonVariants> & {
|
|
49
54
|
asChild?: boolean
|
|
55
|
+
fullWidth?: boolean
|
|
50
56
|
}) {
|
|
51
57
|
const Comp = asChild ? Slot.Root : "button"
|
|
52
58
|
|
|
@@ -55,7 +61,7 @@ function Button({
|
|
|
55
61
|
data-slot="button"
|
|
56
62
|
data-variant={variant}
|
|
57
63
|
data-size={size}
|
|
58
|
-
className={cn(buttonVariants({ variant, size, className }))}
|
|
64
|
+
className={cn(buttonVariants({ variant, size, className }), fullWidth && "w-full")}
|
|
59
65
|
{...props}
|
|
60
66
|
/>
|
|
61
67
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// UI Components (shadcn/ui + reui)
|
|
2
2
|
export * from "./avatar";
|
|
3
|
+
export * from "./badge";
|
|
3
4
|
export * from "./breadcrumb";
|
|
4
5
|
export * from "./button";
|
|
5
6
|
export * from "./button-group";
|
|
@@ -24,6 +25,7 @@ export * from "./scroll-area";
|
|
|
24
25
|
export * from "./select";
|
|
25
26
|
export * from "./separator";
|
|
26
27
|
export * from "./sheet";
|
|
28
|
+
export * from "./space-between";
|
|
27
29
|
export * from "./sidebar";
|
|
28
30
|
export * from "./skeleton";
|
|
29
31
|
export * from "./sonner";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
const spaceBetweenVariants = cva("flex", {
|
|
6
|
+
variants: {
|
|
7
|
+
direction: {
|
|
8
|
+
vertical: "flex-col",
|
|
9
|
+
horizontal: "flex-row",
|
|
10
|
+
},
|
|
11
|
+
size: {
|
|
12
|
+
xxxs: "gap-0.5", // 2px
|
|
13
|
+
xxs: "gap-1", // 4px
|
|
14
|
+
xs: "gap-2", // 8px
|
|
15
|
+
s: "gap-3", // 12px
|
|
16
|
+
m: "gap-4", // 16px
|
|
17
|
+
l: "gap-6", // 24px
|
|
18
|
+
xl: "gap-8", // 32px
|
|
19
|
+
xxl: "gap-10", // 40px
|
|
20
|
+
},
|
|
21
|
+
alignItems: {
|
|
22
|
+
center: "items-center",
|
|
23
|
+
start: "items-start",
|
|
24
|
+
end: "items-end",
|
|
25
|
+
baseline: "items-baseline",
|
|
26
|
+
stretch: "items-stretch",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
direction: "vertical",
|
|
31
|
+
size: "m",
|
|
32
|
+
alignItems: "stretch",
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export interface SpaceBetweenProps
|
|
37
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
38
|
+
VariantProps<typeof spaceBetweenVariants> {}
|
|
39
|
+
|
|
40
|
+
function SpaceBetween({
|
|
41
|
+
className,
|
|
42
|
+
direction,
|
|
43
|
+
size,
|
|
44
|
+
alignItems,
|
|
45
|
+
children,
|
|
46
|
+
...props
|
|
47
|
+
}: SpaceBetweenProps) {
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
data-slot="space-between"
|
|
51
|
+
className={cn(spaceBetweenVariants({ direction, size, alignItems }), className)}
|
|
52
|
+
{...props}
|
|
53
|
+
>
|
|
54
|
+
{children}
|
|
55
|
+
</div>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { SpaceBetween, spaceBetweenVariants }
|
package/src/vite.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Returns the monorepo root directory (platform/).
|
|
6
7
|
* @param {string} currentDir
|
|
7
8
|
* @returns {string}
|
|
8
9
|
*/
|
|
10
|
+
const APP_SHELL_SRC_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const APP_SHELL_PACKAGE_DIR = path.resolve(APP_SHELL_SRC_DIR, "..");
|
|
12
|
+
|
|
9
13
|
function getMonorepoRoot(currentDir) {
|
|
10
14
|
let dir = currentDir;
|
|
11
15
|
while (dir !== "/") {
|
|
@@ -99,9 +103,9 @@ function ssrCssStubPlugin() {
|
|
|
99
103
|
export function getSharedViteConfig(appDir) {
|
|
100
104
|
const monorepoRoot = getMonorepoRoot(appDir);
|
|
101
105
|
const appNodeModules = path.resolve(appDir, "node_modules");
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
const appShellNodeModules =
|
|
106
|
+
const appShellSrc = APP_SHELL_SRC_DIR;
|
|
107
|
+
const packageNodeModules = path.resolve(APP_SHELL_PACKAGE_DIR, "node_modules");
|
|
108
|
+
const appShellNodeModules = fs.existsSync(packageNodeModules) ? packageNodeModules : appNodeModules;
|
|
105
109
|
const appHasDndKit = fs.existsSync(path.resolve(appNodeModules, "@dnd-kit/core"));
|
|
106
110
|
const dndKitNodeModules = appHasDndKit ? appNodeModules : appShellNodeModules;
|
|
107
111
|
|
|
@@ -111,10 +115,6 @@ export function getSharedViteConfig(appDir) {
|
|
|
111
115
|
preserveSymlinks: true,
|
|
112
116
|
alias: [
|
|
113
117
|
// Source aliases for HMR during development
|
|
114
|
-
{
|
|
115
|
-
find: /^@platform\/service-catalog(\/.*)?$/,
|
|
116
|
-
replacement: `${path.resolve(sharedPackages, "service-catalog/src")}$1`,
|
|
117
|
-
},
|
|
118
118
|
{
|
|
119
119
|
find: /^@platform\/app-shell(\/.*)?$/,
|
|
120
120
|
replacement: `${appShellSrc}$1`,
|
package/bin/init.js
DELETED
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @platform/app-shell init
|
|
5
|
-
*
|
|
6
|
-
* Sets up a new app to use the app-shell package correctly.
|
|
7
|
-
* Similar to `shadcn init` but configured for our monorepo structure.
|
|
8
|
-
*
|
|
9
|
-
* Usage (from your app's frontend directory):
|
|
10
|
-
* node ../../../shared/packages/app-shell/bin/init.js
|
|
11
|
-
* node ../../../shared/packages/app-shell/bin/init.js --force
|
|
12
|
-
*
|
|
13
|
-
* Note: npx/bunx won't work - this is a private monorepo package, not published to npm.
|
|
14
|
-
*
|
|
15
|
-
* What it does:
|
|
16
|
-
* 1. Creates minimal app/tailwind.css (delegates to app-shell)
|
|
17
|
-
* 2. Creates components.json (shadcn/ui configuration)
|
|
18
|
-
* 3. Creates app/lib/utils.ts (cn utility + getBasePathHref)
|
|
19
|
-
* 4. Creates tailwind.config.ts
|
|
20
|
-
* 5. Validates vite.config.ts uses getSharedViteConfig()
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import fs from "node:fs";
|
|
24
|
-
import path from "node:path";
|
|
25
|
-
import { fileURLToPath } from "node:url";
|
|
26
|
-
|
|
27
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
28
|
-
const __dirname = path.dirname(__filename);
|
|
29
|
-
const cwd = process.cwd();
|
|
30
|
-
|
|
31
|
-
// ANSI colors
|
|
32
|
-
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
33
|
-
const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
34
|
-
const red = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
35
|
-
const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
|
|
36
|
-
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
37
|
-
|
|
38
|
-
console.log();
|
|
39
|
-
console.log(cyan("@platform/app-shell init"));
|
|
40
|
-
console.log(dim("Setting up app-shell configuration..."));
|
|
41
|
-
console.log();
|
|
42
|
-
|
|
43
|
-
// Templates
|
|
44
|
-
const TAILWIND_CSS = `@import "https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@300;400;500;600;700&display=swap";
|
|
45
|
-
@import "tw-animate-css";
|
|
46
|
-
@import "tailwindcss";
|
|
47
|
-
@import "@platform/app-shell/styles.css";
|
|
48
|
-
@config "../tailwind.config.ts";
|
|
49
|
-
`;
|
|
50
|
-
|
|
51
|
-
// Compute relative path to app-shell from current directory
|
|
52
|
-
function getAppShellRelativePath() {
|
|
53
|
-
// The init script is at app-shell/bin/init.js
|
|
54
|
-
// So app-shell src is at ../src relative to this script
|
|
55
|
-
const appShellSrc = path.resolve(__dirname, "../src");
|
|
56
|
-
const relativePath = path.relative(cwd, appShellSrc);
|
|
57
|
-
return relativePath.replace(/\\/g, "/"); // Normalize for all platforms
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const appShellPath = getAppShellRelativePath();
|
|
61
|
-
|
|
62
|
-
const TAILWIND_CONFIG = `export default {
|
|
63
|
-
darkMode: "class",
|
|
64
|
-
content: [
|
|
65
|
-
"./app/**/*.{ts,tsx,js,jsx}",
|
|
66
|
-
// Include app-shell components for Tailwind to scan
|
|
67
|
-
"${appShellPath}/**/*.{ts,tsx}",
|
|
68
|
-
],
|
|
69
|
-
};
|
|
70
|
-
`;
|
|
71
|
-
|
|
72
|
-
const COMPONENTS_JSON = `{
|
|
73
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
74
|
-
"style": "new-york",
|
|
75
|
-
"rsc": false,
|
|
76
|
-
"tsx": true,
|
|
77
|
-
"tailwind": {
|
|
78
|
-
"config": "tailwind.config.ts",
|
|
79
|
-
"css": "app/tailwind.css",
|
|
80
|
-
"baseColor": "neutral",
|
|
81
|
-
"cssVariables": true,
|
|
82
|
-
"prefix": ""
|
|
83
|
-
},
|
|
84
|
-
"iconLibrary": "lucide",
|
|
85
|
-
"rtl": false,
|
|
86
|
-
"aliases": {
|
|
87
|
-
"components": "~/components",
|
|
88
|
-
"utils": "~/lib/utils",
|
|
89
|
-
"ui": "~/components/ui",
|
|
90
|
-
"lib": "~/lib",
|
|
91
|
-
"hooks": "~/hooks"
|
|
92
|
-
},
|
|
93
|
-
"registries": {}
|
|
94
|
-
}
|
|
95
|
-
`;
|
|
96
|
-
|
|
97
|
-
const UTILS_TS = `import { clsx, type ClassValue } from "clsx"
|
|
98
|
-
import { twMerge } from "tailwind-merge"
|
|
99
|
-
|
|
100
|
-
export function cn(...inputs: ClassValue[]) {
|
|
101
|
-
return twMerge(clsx(inputs))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Returns a path with the VITE_BASE_PATH prefix for use in href attributes.
|
|
106
|
-
* React Router's navigate() handles basename automatically, but href attributes
|
|
107
|
-
* on Cloudscape Link components (or native <a> tags) do not.
|
|
108
|
-
*
|
|
109
|
-
* @param path - The relative path (e.g., "/clients/123" or "/scheduling/abc")
|
|
110
|
-
* @returns The path prefixed with the base path (e.g., "/client-management/clients/123")
|
|
111
|
-
*/
|
|
112
|
-
export function getBasePathHref(path: string): string {
|
|
113
|
-
const configuredBasePath = import.meta.env.VITE_BASE_PATH;
|
|
114
|
-
if (typeof configuredBasePath !== "string") {
|
|
115
|
-
throw new Error("VITE_BASE_PATH must be defined");
|
|
116
|
-
}
|
|
117
|
-
const basePath = configuredBasePath.replace(/\\/$/, "");
|
|
118
|
-
const normalizedPath = path.startsWith("/") ? path : \`/\${path}\`;
|
|
119
|
-
if (basePath === "" || basePath === "/") {
|
|
120
|
-
return normalizedPath;
|
|
121
|
-
}
|
|
122
|
-
return \`\${basePath}\${normalizedPath}\`;
|
|
123
|
-
}
|
|
124
|
-
`;
|
|
125
|
-
|
|
126
|
-
// Helper functions
|
|
127
|
-
function ensureDir(dir) {
|
|
128
|
-
if (!fs.existsSync(dir)) {
|
|
129
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function writeFile(filePath, content, overwrite = false) {
|
|
134
|
-
const relativePath = path.relative(cwd, filePath);
|
|
135
|
-
|
|
136
|
-
if (fs.existsSync(filePath) && !overwrite) {
|
|
137
|
-
// Check if content is different
|
|
138
|
-
const existing = fs.readFileSync(filePath, "utf-8");
|
|
139
|
-
if (existing === content) {
|
|
140
|
-
console.log(dim(` ${relativePath} (unchanged)`));
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
console.log(yellow(` ${relativePath} (exists, skipping - use --force to overwrite)`));
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
fs.writeFileSync(filePath, content);
|
|
148
|
-
console.log(green(` ${relativePath}`));
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function checkViteConfig() {
|
|
153
|
-
const viteConfigPath = path.join(cwd, "vite.config.ts");
|
|
154
|
-
if (!fs.existsSync(viteConfigPath)) {
|
|
155
|
-
console.log(yellow(" vite.config.ts not found - skipping validation"));
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const content = fs.readFileSync(viteConfigPath, "utf-8");
|
|
160
|
-
|
|
161
|
-
if (!content.includes("getSharedViteConfig")) {
|
|
162
|
-
console.log();
|
|
163
|
-
console.log(yellow("Warning: vite.config.ts does not use getSharedViteConfig()"));
|
|
164
|
-
console.log(dim("Consider updating it to use the shared config:"));
|
|
165
|
-
console.log();
|
|
166
|
-
console.log(dim(` import { getSharedViteConfig } from "@platform/app-shell/vite";`));
|
|
167
|
-
console.log(dim(` import { mergeConfig } from "vite";`));
|
|
168
|
-
console.log();
|
|
169
|
-
console.log(dim(` export default defineConfig(({ mode }) => {`));
|
|
170
|
-
console.log(dim(` const shared = getSharedViteConfig(__dirname);`));
|
|
171
|
-
console.log(dim(` return mergeConfig(shared, { /* app-specific config */ });`));
|
|
172
|
-
console.log(dim(` });`));
|
|
173
|
-
} else {
|
|
174
|
-
console.log(green(" vite.config.ts uses getSharedViteConfig()"));
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function checkConflictingCss() {
|
|
179
|
-
// Check for app.css or other CSS files that might conflict with app-shell
|
|
180
|
-
const conflictingFiles = ["app/app.css", "app/global.css", "app/globals.css"];
|
|
181
|
-
const found = [];
|
|
182
|
-
|
|
183
|
-
for (const file of conflictingFiles) {
|
|
184
|
-
const filePath = path.join(cwd, file);
|
|
185
|
-
if (fs.existsSync(filePath)) {
|
|
186
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
187
|
-
// Check if it has html/body/root blocks with hardcoded colors
|
|
188
|
-
// These patterns specifically target global style overrides
|
|
189
|
-
const hasGlobalColorOverride =
|
|
190
|
-
/(?:html|body|\:root)\s*\{[^}]*(?:background-color|background|color)\s*:/i.test(content);
|
|
191
|
-
|
|
192
|
-
if (hasGlobalColorOverride) {
|
|
193
|
-
found.push(file);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (found.length > 0) {
|
|
199
|
-
console.log();
|
|
200
|
-
console.log(yellow("Warning: Found CSS files that may conflict with app-shell:"));
|
|
201
|
-
for (const file of found) {
|
|
202
|
-
console.log(red(` ${file}`));
|
|
203
|
-
}
|
|
204
|
-
console.log(dim("These files have html/body/:root blocks with hardcoded colors."));
|
|
205
|
-
console.log(dim("Remove these blocks and rely on app-shell/styles.css for theming."));
|
|
206
|
-
} else {
|
|
207
|
-
console.log(green(" No conflicting CSS files found"));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Check for --force flag
|
|
212
|
-
const force = process.argv.includes("--force") || process.argv.includes("-f");
|
|
213
|
-
|
|
214
|
-
// Preflight checks
|
|
215
|
-
console.log("Preflight checks:");
|
|
216
|
-
|
|
217
|
-
// Check if we're in a frontend directory
|
|
218
|
-
const packageJsonPath = path.join(cwd, "package.json");
|
|
219
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
220
|
-
console.log(red(" package.json not found"));
|
|
221
|
-
console.log(dim(" Run this command from your frontend directory"));
|
|
222
|
-
process.exit(1);
|
|
223
|
-
}
|
|
224
|
-
console.log(green(" Found package.json"));
|
|
225
|
-
|
|
226
|
-
// Check for app directory (React Router convention)
|
|
227
|
-
const appDir = path.join(cwd, "app");
|
|
228
|
-
if (!fs.existsSync(appDir)) {
|
|
229
|
-
console.log(yellow(" app/ directory not found - will create it"));
|
|
230
|
-
}
|
|
231
|
-
console.log(green(" Found app/ directory"));
|
|
232
|
-
|
|
233
|
-
// Check for @platform/app-shell dependency
|
|
234
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
235
|
-
const hasAppShell = packageJson.dependencies?.["@platform/app-shell"] ||
|
|
236
|
-
packageJson.devDependencies?.["@platform/app-shell"];
|
|
237
|
-
if (!hasAppShell) {
|
|
238
|
-
console.log(yellow(" @platform/app-shell not in dependencies"));
|
|
239
|
-
console.log(dim(" Add it: \"@platform/app-shell\": \"file:../../../shared/packages/app-shell\""));
|
|
240
|
-
} else {
|
|
241
|
-
console.log(green(" Found @platform/app-shell dependency"));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
console.log();
|
|
245
|
-
console.log("Creating files:");
|
|
246
|
-
|
|
247
|
-
// Ensure directories exist
|
|
248
|
-
ensureDir(path.join(cwd, "app"));
|
|
249
|
-
ensureDir(path.join(cwd, "app/lib"));
|
|
250
|
-
|
|
251
|
-
// Create files
|
|
252
|
-
writeFile(path.join(cwd, "app/tailwind.css"), TAILWIND_CSS, force);
|
|
253
|
-
writeFile(path.join(cwd, "tailwind.config.ts"), TAILWIND_CONFIG, force);
|
|
254
|
-
writeFile(path.join(cwd, "components.json"), COMPONENTS_JSON, force);
|
|
255
|
-
writeFile(path.join(cwd, "app/lib/utils.ts"), UTILS_TS, force);
|
|
256
|
-
|
|
257
|
-
console.log();
|
|
258
|
-
console.log("Validating configuration:");
|
|
259
|
-
checkViteConfig();
|
|
260
|
-
checkConflictingCss();
|
|
261
|
-
|
|
262
|
-
console.log();
|
|
263
|
-
console.log(green("Done!"));
|
|
264
|
-
console.log();
|
|
265
|
-
console.log("Next steps:");
|
|
266
|
-
console.log(dim(" 1. Run 'bun install' to install dependencies"));
|
|
267
|
-
console.log(dim(" 2. Import '@platform/app-shell' in your layout component"));
|
|
268
|
-
console.log(dim(" 3. Run 'bun run dev' to start the dev server"));
|
|
269
|
-
console.log();
|