radtools 0.1.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/README.md +108 -0
- package/bin/radtools.js +5 -0
- package/dist/cli/index.js +427 -0
- package/package.json +55 -0
- package/templates/api-routes/assets/optimize/route.ts +94 -0
- package/templates/api-routes/assets/route.ts +159 -0
- package/templates/api-routes/components/create-folder/route.ts +55 -0
- package/templates/api-routes/components/route.ts +156 -0
- package/templates/api-routes/fonts/route.ts +96 -0
- package/templates/api-routes/fonts/upload/route.ts +79 -0
- package/templates/api-routes/read-css/route.ts +29 -0
- package/templates/api-routes/write-css/route.ts +423 -0
- package/templates/components/Rad_os/AppWindow.tsx +423 -0
- package/templates/components/Rad_os/MobileAppModal.tsx +76 -0
- package/templates/components/Rad_os/WindowTitleBar.tsx +290 -0
- package/templates/components/icons/Icon.tsx +224 -0
- package/templates/components/icons/README.md +85 -0
- package/templates/components/icons/index.ts +20 -0
- package/templates/components/icons.tsx +164 -0
- package/templates/components/ui/Accordion.tsx +268 -0
- package/templates/components/ui/Alert.tsx +111 -0
- package/templates/components/ui/Badge.tsx +87 -0
- package/templates/components/ui/Breadcrumbs.tsx +88 -0
- package/templates/components/ui/Button.tsx +249 -0
- package/templates/components/ui/Card.tsx +137 -0
- package/templates/components/ui/Checkbox.tsx +137 -0
- package/templates/components/ui/ContextMenu.tsx +220 -0
- package/templates/components/ui/Dialog.tsx +264 -0
- package/templates/components/ui/Divider.tsx +70 -0
- package/templates/components/ui/DropdownMenu.tsx +301 -0
- package/templates/components/ui/HelpPanel.tsx +119 -0
- package/templates/components/ui/Input.tsx +176 -0
- package/templates/components/ui/Popover.tsx +211 -0
- package/templates/components/ui/Progress.tsx +158 -0
- package/templates/components/ui/Select.tsx +134 -0
- package/templates/components/ui/Sheet.tsx +316 -0
- package/templates/components/ui/Slider.tsx +223 -0
- package/templates/components/ui/Switch.tsx +155 -0
- package/templates/components/ui/Tabs.tsx +253 -0
- package/templates/components/ui/Toast.tsx +192 -0
- package/templates/components/ui/Tooltip.tsx +129 -0
- package/templates/components/ui/hooks/useModalBehavior.ts +66 -0
- package/templates/components/ui/index.ts +84 -0
- package/templates/devtools/DevToolsPanel.tsx +261 -0
- package/templates/devtools/DevToolsProvider.tsx +43 -0
- package/templates/devtools/components/BreakpointIndicator.tsx +49 -0
- package/templates/devtools/components/ColorPicker.tsx +33 -0
- package/templates/devtools/components/ComponentsSecondaryNav.tsx +44 -0
- package/templates/devtools/components/ContextualFooter.tsx +56 -0
- package/templates/devtools/components/DraggablePanel.tsx +43 -0
- package/templates/devtools/components/PrimaryNavigationFooter.tsx +254 -0
- package/templates/devtools/components/SearchableColorDropdown.tsx +253 -0
- package/templates/devtools/components/SecondaryNavigation.tsx +36 -0
- package/templates/devtools/components/TokenDropdown.tsx +47 -0
- package/templates/devtools/components/TypographyFooter.tsx +145 -0
- package/templates/devtools/hooks/useMockState.ts +16 -0
- package/templates/devtools/index.ts +17 -0
- package/templates/devtools/lib/componentScanner.ts +78 -0
- package/templates/devtools/lib/cssParser.ts +465 -0
- package/templates/devtools/lib/searchIndexes.ts +45 -0
- package/templates/devtools/lib/selectorGenerator.ts +86 -0
- package/templates/devtools/store/index.ts +66 -0
- package/templates/devtools/store/slices/assetsSlice.ts +106 -0
- package/templates/devtools/store/slices/componentsSlice.ts +59 -0
- package/templates/devtools/store/slices/mockStatesSlice.ts +77 -0
- package/templates/devtools/store/slices/panelSlice.ts +17 -0
- package/templates/devtools/store/slices/typographySlice.ts +538 -0
- package/templates/devtools/store/slices/variablesSlice.ts +167 -0
- package/templates/devtools/tabs/AssetsTab/AssetGrid.tsx +76 -0
- package/templates/devtools/tabs/AssetsTab/FolderTree.tsx +53 -0
- package/templates/devtools/tabs/AssetsTab/UploadDropzone.tsx +76 -0
- package/templates/devtools/tabs/AssetsTab/index.tsx +182 -0
- package/templates/devtools/tabs/ComponentsTab/AddTabButton.tsx +63 -0
- package/templates/devtools/tabs/ComponentsTab/ComponentList.tsx +153 -0
- package/templates/devtools/tabs/ComponentsTab/DesignSystemTab.tsx +1515 -0
- package/templates/devtools/tabs/ComponentsTab/DynamicFolderTab.tsx +113 -0
- package/templates/devtools/tabs/ComponentsTab/PropDisplay.tsx +55 -0
- package/templates/devtools/tabs/ComponentsTab/index.tsx +167 -0
- package/templates/devtools/tabs/ComponentsTab/previews/.gitkeep +4 -0
- package/templates/devtools/tabs/ComponentsTab/previews/Rad_os.tsx +262 -0
- package/templates/devtools/tabs/ComponentsTab/tabConfig.ts +53 -0
- package/templates/devtools/tabs/MockStatesTab/index.tsx +29 -0
- package/templates/devtools/tabs/TypographyTab/FontManager.tsx +421 -0
- package/templates/devtools/tabs/TypographyTab/TypographyStylesDisplay.tsx +290 -0
- package/templates/devtools/tabs/TypographyTab/index.tsx +98 -0
- package/templates/devtools/tabs/VariablesTab/BaseColorEditor.tsx +267 -0
- package/templates/devtools/tabs/VariablesTab/BorderRadiusEditor.tsx +37 -0
- package/templates/devtools/tabs/VariablesTab/ColorModeSelector.tsx +235 -0
- package/templates/devtools/tabs/VariablesTab/index.tsx +100 -0
- package/templates/devtools/types/index.ts +99 -0
- package/templates/globals.css +574 -0
- package/templates/hooks/index.ts +1 -0
- package/templates/hooks/useWindowManager.ts +212 -0
- package/templates/public/assets/icons/avatar.svg +18 -0
- package/templates/public/assets/icons/checkmark-filled.svg +14 -0
- package/templates/public/assets/icons/checkmark.svg +14 -0
- package/templates/public/assets/icons/chevron-down.svg +14 -0
- package/templates/public/assets/icons/close.svg +14 -0
- package/templates/public/assets/icons/copy.svg +14 -0
- package/templates/public/assets/icons/download.svg +14 -0
- package/templates/public/assets/icons/expand.svg +31 -0
- package/templates/public/assets/icons/file-blank.svg +17 -0
- package/templates/public/assets/icons/file-image.svg +19 -0
- package/templates/public/assets/icons/file-written.svg +17 -0
- package/templates/public/assets/icons/folder-closed.svg +17 -0
- package/templates/public/assets/icons/folder-open.svg +17 -0
- package/templates/public/assets/icons/hamburger.svg +18 -0
- package/templates/public/assets/icons/home-outline.svg +28 -0
- package/templates/public/assets/icons/home.svg +30 -0
- package/templates/public/assets/icons/hourglass.svg +25 -0
- package/templates/public/assets/icons/information-circle.svg +14 -0
- package/templates/public/assets/icons/information.svg +17 -0
- package/templates/public/assets/icons/lightning.svg +14 -0
- package/templates/public/assets/icons/locked.svg +17 -0
- package/templates/public/assets/icons/not-allowed.svg +14 -0
- package/templates/public/assets/icons/plus.svg +5 -0
- package/templates/public/assets/icons/power-thin.svg +17 -0
- package/templates/public/assets/icons/power.svg +17 -0
- package/templates/public/assets/icons/question-block.svg +14 -0
- package/templates/public/assets/icons/question.svg +17 -0
- package/templates/public/assets/icons/refresh-block.svg +14 -0
- package/templates/public/assets/icons/refresh.svg +17 -0
- package/templates/public/assets/icons/save.svg +14 -0
- package/templates/public/assets/icons/search.svg +25 -0
- package/templates/public/assets/icons/settings.svg +14 -0
- package/templates/public/assets/icons/trash-full.svg +21 -0
- package/templates/public/assets/icons/trash-open.svg +23 -0
- package/templates/public/assets/icons/trash.svg +18 -0
- package/templates/public/assets/icons/unlocked.svg +17 -0
- package/templates/public/assets/icons/waring-triangle-filled.svg +17 -0
- package/templates/public/assets/icons/warning-triangle-filled-2.svg +30 -0
- package/templates/public/assets/icons/warning-triangle-lines.svg +29 -0
- package/templates/public/assets/icons/wrench.svg +17 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { StateCreator } from 'zustand';
|
|
2
|
+
import type { AssetFolder, AssetFile } from '../../types';
|
|
3
|
+
|
|
4
|
+
export interface AssetsSlice {
|
|
5
|
+
// State
|
|
6
|
+
assets: AssetFolder | null;
|
|
7
|
+
selectedFolder: string | null;
|
|
8
|
+
uploadProgress: Record<string, number>;
|
|
9
|
+
isLoading: boolean;
|
|
10
|
+
|
|
11
|
+
// Actions
|
|
12
|
+
setAssets: (assets: AssetFolder) => void;
|
|
13
|
+
setSelectedFolder: (path: string | null) => void;
|
|
14
|
+
setUploadProgress: (fileName: string, progress: number) => void;
|
|
15
|
+
clearUploadProgress: (fileName: string) => void;
|
|
16
|
+
refreshAssets: () => Promise<void>;
|
|
17
|
+
uploadAsset: (file: File, folder: string) => Promise<void>;
|
|
18
|
+
deleteAsset: (path: string) => Promise<void>;
|
|
19
|
+
optimizeAssets: (paths: string[]) => Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const createAssetsSlice: StateCreator<AssetsSlice, [], [], AssetsSlice> = (set, get) => ({
|
|
23
|
+
assets: null,
|
|
24
|
+
selectedFolder: null,
|
|
25
|
+
uploadProgress: {},
|
|
26
|
+
isLoading: false,
|
|
27
|
+
|
|
28
|
+
setAssets: (assets) => set({ assets }),
|
|
29
|
+
|
|
30
|
+
setSelectedFolder: (path) => set({ selectedFolder: path }),
|
|
31
|
+
|
|
32
|
+
setUploadProgress: (fileName, progress) => set((state) => ({
|
|
33
|
+
uploadProgress: { ...state.uploadProgress, [fileName]: progress }
|
|
34
|
+
})),
|
|
35
|
+
|
|
36
|
+
clearUploadProgress: (fileName) => set((state) => {
|
|
37
|
+
const { [fileName]: _, ...rest } = state.uploadProgress;
|
|
38
|
+
return { uploadProgress: rest };
|
|
39
|
+
}),
|
|
40
|
+
|
|
41
|
+
refreshAssets: async () => {
|
|
42
|
+
set({ isLoading: true });
|
|
43
|
+
try {
|
|
44
|
+
const res = await fetch('/api/devtools/assets');
|
|
45
|
+
const data = await res.json();
|
|
46
|
+
set({ assets: data.assets, isLoading: false });
|
|
47
|
+
} catch (error) {
|
|
48
|
+
set({ isLoading: false });
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
uploadAsset: async (file, folder) => {
|
|
53
|
+
const formData = new FormData();
|
|
54
|
+
formData.append('file', file);
|
|
55
|
+
formData.append('folder', folder);
|
|
56
|
+
|
|
57
|
+
set((state) => ({
|
|
58
|
+
uploadProgress: { ...state.uploadProgress, [file.name]: 0 }
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const res = await fetch('/api/devtools/assets', {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
body: formData,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (res.ok) {
|
|
68
|
+
set((state) => ({
|
|
69
|
+
uploadProgress: { ...state.uploadProgress, [file.name]: 100 }
|
|
70
|
+
}));
|
|
71
|
+
await get().refreshAssets();
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
// Failed to upload asset
|
|
75
|
+
} finally {
|
|
76
|
+
setTimeout(() => get().clearUploadProgress(file.name), 2000);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
deleteAsset: async (path) => {
|
|
81
|
+
try {
|
|
82
|
+
await fetch('/api/devtools/assets', {
|
|
83
|
+
method: 'DELETE',
|
|
84
|
+
headers: { 'Content-Type': 'application/json' },
|
|
85
|
+
body: JSON.stringify({ path }),
|
|
86
|
+
});
|
|
87
|
+
await get().refreshAssets();
|
|
88
|
+
} catch (error) {
|
|
89
|
+
// Failed to delete asset
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
|
|
93
|
+
optimizeAssets: async (paths) => {
|
|
94
|
+
try {
|
|
95
|
+
await fetch('/api/devtools/assets/optimize', {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
headers: { 'Content-Type': 'application/json' },
|
|
98
|
+
body: JSON.stringify({ files: paths }),
|
|
99
|
+
});
|
|
100
|
+
await get().refreshAssets();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
// Failed to optimize assets
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { StateCreator } from 'zustand';
|
|
2
|
+
import type { DiscoveredComponent } from '../../types';
|
|
3
|
+
|
|
4
|
+
export interface ComponentsSlice {
|
|
5
|
+
// State
|
|
6
|
+
components: DiscoveredComponent[];
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
lastScanned: string | null;
|
|
9
|
+
|
|
10
|
+
// Actions
|
|
11
|
+
setComponents: (components: DiscoveredComponent[]) => void;
|
|
12
|
+
setIsLoading: (loading: boolean) => void;
|
|
13
|
+
scanComponents: () => Promise<void>;
|
|
14
|
+
refreshComponents: () => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const createComponentsSlice: StateCreator<ComponentsSlice, [], [], ComponentsSlice> = (set) => ({
|
|
18
|
+
components: [],
|
|
19
|
+
isLoading: false,
|
|
20
|
+
lastScanned: null,
|
|
21
|
+
|
|
22
|
+
setComponents: (components) => set({
|
|
23
|
+
components,
|
|
24
|
+
lastScanned: new Date().toISOString()
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
setIsLoading: (isLoading) => set({ isLoading }),
|
|
28
|
+
|
|
29
|
+
scanComponents: async () => {
|
|
30
|
+
set({ isLoading: true });
|
|
31
|
+
try {
|
|
32
|
+
const res = await fetch('/api/devtools/components');
|
|
33
|
+
const data = await res.json();
|
|
34
|
+
set({
|
|
35
|
+
components: data.components || [],
|
|
36
|
+
lastScanned: new Date().toISOString(),
|
|
37
|
+
isLoading: false
|
|
38
|
+
});
|
|
39
|
+
} catch (error) {
|
|
40
|
+
set({ isLoading: false });
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
refreshComponents: async () => {
|
|
45
|
+
set({ isLoading: true });
|
|
46
|
+
try {
|
|
47
|
+
const res = await fetch('/api/devtools/components');
|
|
48
|
+
const data = await res.json();
|
|
49
|
+
set({
|
|
50
|
+
components: data.components || [],
|
|
51
|
+
lastScanned: new Date().toISOString(),
|
|
52
|
+
isLoading: false
|
|
53
|
+
});
|
|
54
|
+
} catch (error) {
|
|
55
|
+
set({ isLoading: false });
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { StateCreator } from 'zustand';
|
|
2
|
+
import type { MockState } from '../../types';
|
|
3
|
+
|
|
4
|
+
export interface MockStatesSlice {
|
|
5
|
+
// State
|
|
6
|
+
mockStates: MockState[];
|
|
7
|
+
|
|
8
|
+
// Actions
|
|
9
|
+
toggleMockState: (id: string) => void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Default preset states
|
|
13
|
+
const defaultPresets: MockState[] = [
|
|
14
|
+
{
|
|
15
|
+
id: 'wallet-connected',
|
|
16
|
+
name: 'Wallet Connected',
|
|
17
|
+
description: 'Simulates a connected wallet',
|
|
18
|
+
category: 'wallet',
|
|
19
|
+
values: {
|
|
20
|
+
isConnected: true,
|
|
21
|
+
address: '0x1234567890abcdef1234567890abcdef12345678',
|
|
22
|
+
balance: '1.5',
|
|
23
|
+
},
|
|
24
|
+
active: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'wallet-disconnected',
|
|
28
|
+
name: 'Wallet Disconnected',
|
|
29
|
+
description: 'Simulates a disconnected wallet',
|
|
30
|
+
category: 'wallet',
|
|
31
|
+
values: {
|
|
32
|
+
isConnected: false,
|
|
33
|
+
address: null,
|
|
34
|
+
balance: '0',
|
|
35
|
+
},
|
|
36
|
+
active: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'token-hodler',
|
|
40
|
+
name: 'Token Hodler',
|
|
41
|
+
description: 'Simulates a user holding tokens',
|
|
42
|
+
category: 'wallet',
|
|
43
|
+
values: {
|
|
44
|
+
isConnected: true,
|
|
45
|
+
address: '0x1234567890abcdef1234567890abcdef12345678',
|
|
46
|
+
balance: '10.5',
|
|
47
|
+
hasTokens: true,
|
|
48
|
+
},
|
|
49
|
+
active: false,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
export const createMockStatesSlice: StateCreator<MockStatesSlice, [], [], MockStatesSlice> = (set) => ({
|
|
54
|
+
mockStates: defaultPresets,
|
|
55
|
+
|
|
56
|
+
toggleMockState: (id) => set((state) => {
|
|
57
|
+
const targetState = state.mockStates.find((m) => m.id === id);
|
|
58
|
+
if (!targetState) return state;
|
|
59
|
+
|
|
60
|
+
// If activating, deactivate other states in the same category
|
|
61
|
+
const newActive = !targetState.active;
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
mockStates: state.mockStates.map((m) => {
|
|
65
|
+
if (m.id === id) {
|
|
66
|
+
return { ...m, active: newActive };
|
|
67
|
+
}
|
|
68
|
+
// Deactivate other states in the same category
|
|
69
|
+
if (newActive && m.category === targetState.category && m.active) {
|
|
70
|
+
return { ...m, active: false };
|
|
71
|
+
}
|
|
72
|
+
return m;
|
|
73
|
+
})
|
|
74
|
+
};
|
|
75
|
+
}),
|
|
76
|
+
});
|
|
77
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { StateCreator } from 'zustand';
|
|
2
|
+
|
|
3
|
+
export interface PanelSlice {
|
|
4
|
+
// Fullscreen state (NOT persisted)
|
|
5
|
+
isFullscreen: boolean;
|
|
6
|
+
toggleFullscreen: () => void;
|
|
7
|
+
setFullscreen: (value: boolean) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const createPanelSlice: StateCreator<PanelSlice, [], [], PanelSlice> = (set) => ({
|
|
11
|
+
isFullscreen: false,
|
|
12
|
+
|
|
13
|
+
toggleFullscreen: () => set((state) => ({ isFullscreen: !state.isFullscreen })),
|
|
14
|
+
|
|
15
|
+
setFullscreen: (value) => set({ isFullscreen: value }),
|
|
16
|
+
});
|
|
17
|
+
|