create-chaaskit 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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +25 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add-infra.d.ts +6 -0
- package/dist/commands/add-infra.d.ts.map +1 -0
- package/dist/commands/add-infra.js +160 -0
- package/dist/commands/add-infra.js.map +1 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +63 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/db-sync.d.ts +13 -0
- package/dist/commands/db-sync.d.ts.map +1 -0
- package/dist/commands/db-sync.js +108 -0
- package/dist/commands/db-sync.js.map +1 -0
- package/dist/commands/dev.d.ts +7 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +61 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +214 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/.env.example +24 -0
- package/dist/templates/README.md +81 -0
- package/dist/templates/app/components/AcceptInviteClient.tsx +10 -0
- package/dist/templates/app/components/AdminDashboardClient.tsx +10 -0
- package/dist/templates/app/components/AdminTeamClient.tsx +10 -0
- package/dist/templates/app/components/AdminTeamsClient.tsx +10 -0
- package/dist/templates/app/components/AdminUsersClient.tsx +10 -0
- package/dist/templates/app/components/ApiKeysClient.tsx +10 -0
- package/dist/templates/app/components/AutomationsClient.tsx +10 -0
- package/dist/templates/app/components/ChatClient.tsx +13 -0
- package/dist/templates/app/components/ClientOnly.tsx +6 -0
- package/dist/templates/app/components/DocumentsClient.tsx +10 -0
- package/dist/templates/app/components/OAuthConsentClient.tsx +10 -0
- package/dist/templates/app/components/PricingClient.tsx +10 -0
- package/dist/templates/app/components/TeamSettingsClient.tsx +10 -0
- package/dist/templates/app/components/VerifyEmailClient.tsx +10 -0
- package/dist/templates/app/entry.client.tsx +12 -0
- package/dist/templates/app/entry.server.tsx +67 -0
- package/dist/templates/app/root.tsx +91 -0
- package/dist/templates/app/routes/_index.tsx +82 -0
- package/dist/templates/app/routes/admin._index.tsx +57 -0
- package/dist/templates/app/routes/admin.teams.$teamId.tsx +57 -0
- package/dist/templates/app/routes/admin.teams._index.tsx +57 -0
- package/dist/templates/app/routes/admin.users.tsx +57 -0
- package/dist/templates/app/routes/api-keys.tsx +57 -0
- package/dist/templates/app/routes/automations.tsx +57 -0
- package/dist/templates/app/routes/chat._index.tsx +11 -0
- package/dist/templates/app/routes/chat.admin._index.tsx +10 -0
- package/dist/templates/app/routes/chat.admin.teams.$teamId.tsx +10 -0
- package/dist/templates/app/routes/chat.admin.teams._index.tsx +10 -0
- package/dist/templates/app/routes/chat.admin.users.tsx +10 -0
- package/dist/templates/app/routes/chat.api-keys.tsx +10 -0
- package/dist/templates/app/routes/chat.automations.tsx +10 -0
- package/dist/templates/app/routes/chat.documents.tsx +10 -0
- package/dist/templates/app/routes/chat.team.$teamId.settings.tsx +10 -0
- package/dist/templates/app/routes/chat.thread.$threadId.tsx +11 -0
- package/dist/templates/app/routes/chat.tsx +39 -0
- package/dist/templates/app/routes/documents.tsx +57 -0
- package/dist/templates/app/routes/invite.$token.tsx +10 -0
- package/dist/templates/app/routes/login.tsx +334 -0
- package/dist/templates/app/routes/oauth.consent.tsx +10 -0
- package/dist/templates/app/routes/pricing.tsx +10 -0
- package/dist/templates/app/routes/privacy.tsx +197 -0
- package/dist/templates/app/routes/register.tsx +398 -0
- package/dist/templates/app/routes/shared.$shareId.tsx +226 -0
- package/dist/templates/app/routes/team.$teamId.settings.tsx +57 -0
- package/dist/templates/app/routes/terms.tsx +173 -0
- package/dist/templates/app/routes/thread.$threadId.tsx +102 -0
- package/dist/templates/app/routes/verify-email.tsx +10 -0
- package/dist/templates/app/routes.ts +47 -0
- package/dist/templates/config/app.config.ts +216 -0
- package/dist/templates/docs/admin.md +257 -0
- package/dist/templates/docs/api-keys.md +403 -0
- package/dist/templates/docs/authentication.md +247 -0
- package/dist/templates/docs/configuration.md +1212 -0
- package/dist/templates/docs/custom-pages.md +466 -0
- package/dist/templates/docs/deployment.md +362 -0
- package/dist/templates/docs/development.md +411 -0
- package/dist/templates/docs/documents.md +293 -0
- package/dist/templates/docs/extensions.md +639 -0
- package/dist/templates/docs/index.md +139 -0
- package/dist/templates/docs/installation.md +286 -0
- package/dist/templates/docs/mcp.md +952 -0
- package/dist/templates/docs/native-tools.md +688 -0
- package/dist/templates/docs/queue.md +514 -0
- package/dist/templates/docs/scheduled-prompts.md +279 -0
- package/dist/templates/docs/settings.md +415 -0
- package/dist/templates/docs/slack.md +318 -0
- package/dist/templates/docs/styling.md +288 -0
- package/dist/templates/extensions/agents/.gitkeep +0 -0
- package/dist/templates/extensions/pages/.gitkeep +0 -0
- package/dist/templates/extensions/payment-plans/.gitkeep +0 -0
- package/dist/templates/index.html +16 -0
- package/dist/templates/infra-aws/.github/workflows/deploy.yml +95 -0
- package/dist/templates/infra-aws/README.md +207 -0
- package/dist/templates/infra-aws/bin/cdk.ts +18 -0
- package/dist/templates/infra-aws/cdk.json +43 -0
- package/dist/templates/infra-aws/config/deployment.ts +156 -0
- package/dist/templates/infra-aws/lib/chaaskit-stack.ts +419 -0
- package/dist/templates/infra-aws/package.json +27 -0
- package/dist/templates/infra-aws/scripts/build-app.sh +63 -0
- package/dist/templates/infra-aws/tsconfig.json +25 -0
- package/dist/templates/package.json +46 -0
- package/dist/templates/prisma/schema/base.prisma +584 -0
- package/dist/templates/prisma/schema/custom.prisma +24 -0
- package/dist/templates/prisma/schema.prisma +271 -0
- package/dist/templates/public/favicon.svg +4 -0
- package/dist/templates/public/logo.svg +4 -0
- package/dist/templates/react-router.config.ts +11 -0
- package/dist/templates/server.js +52 -0
- package/dist/templates/src/main.tsx +8 -0
- package/dist/templates/tsconfig.json +26 -0
- package/dist/templates/vite.config.ts +26 -0
- package/package.json +46 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Slack Integration
|
|
2
|
+
|
|
3
|
+
Connect your team's Slack workspace to chat with your AI assistant directly from Slack. Team members can @mention the bot in any channel to get instant AI responses.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AI Chat via @mentions**: Mention your bot in any channel to get AI responses
|
|
8
|
+
- **Thread Continuity**: Follow-up messages in a Slack thread maintain conversation context
|
|
9
|
+
- **Team Notifications**: Get notified in Slack when threads are shared, messages are liked, or new members join
|
|
10
|
+
- **Per-Team Configuration**: Each team can connect their own Slack workspace
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
Before enabling Slack integration, you need:
|
|
15
|
+
|
|
16
|
+
1. **Teams feature enabled** - Slack integration requires the teams feature
|
|
17
|
+
2. **A Slack App** - Create one at https://api.slack.com/apps
|
|
18
|
+
|
|
19
|
+
## Creating a Slack App
|
|
20
|
+
|
|
21
|
+
### 1. Create the App
|
|
22
|
+
|
|
23
|
+
1. Go to https://api.slack.com/apps
|
|
24
|
+
2. Click "Create New App" → "From scratch"
|
|
25
|
+
3. Name your app and select your workspace
|
|
26
|
+
4. Note the **Client ID**, **Client Secret**, and **Signing Secret** from "Basic Information"
|
|
27
|
+
|
|
28
|
+
### 2. Configure Bot Token Scopes
|
|
29
|
+
|
|
30
|
+
Go to "OAuth & Permissions" and add these Bot Token Scopes:
|
|
31
|
+
|
|
32
|
+
| Scope | Purpose |
|
|
33
|
+
|-------|---------|
|
|
34
|
+
| `app_mentions:read` | Receive @mention events |
|
|
35
|
+
| `channels:history` | Read channel messages for thread context |
|
|
36
|
+
| `groups:history` | Read private channel messages |
|
|
37
|
+
| `im:history` | Read direct messages |
|
|
38
|
+
| `chat:write` | Send messages as the bot |
|
|
39
|
+
| `reactions:write` | Add reactions (processing indicators) |
|
|
40
|
+
| `users:read` | Look up user information |
|
|
41
|
+
|
|
42
|
+
### 3. Enable Event Subscriptions
|
|
43
|
+
|
|
44
|
+
1. Go to "Event Subscriptions"
|
|
45
|
+
2. Turn on "Enable Events"
|
|
46
|
+
3. Set the Request URL to: `{API_URL}/api/slack/events` (e.g., `https://api.your-app.com/api/slack/events`)
|
|
47
|
+
4. Subscribe to these bot events:
|
|
48
|
+
- `app_mention` - When someone @mentions your bot
|
|
49
|
+
- `message.channels` - Messages in public channels (optional, for DM support)
|
|
50
|
+
- `message.groups` - Messages in private channels (optional)
|
|
51
|
+
- `message.im` - Direct messages to the bot (optional)
|
|
52
|
+
|
|
53
|
+
### 4. Set OAuth Redirect URL
|
|
54
|
+
|
|
55
|
+
1. Go to "OAuth & Permissions"
|
|
56
|
+
2. Add a Redirect URL: `{API_URL}/api/slack/callback` (e.g., `https://api.your-app.com/api/slack/callback`)
|
|
57
|
+
|
|
58
|
+
### Sample App Manifest
|
|
59
|
+
|
|
60
|
+
You can use this manifest as a starting point when creating your Slack app. Go to "App Manifest" in your app settings and paste this JSON (update the URLs to match your deployment):
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"display_information": {
|
|
65
|
+
"name": "My AI Assistant",
|
|
66
|
+
"description": "Chat with AI directly in Slack",
|
|
67
|
+
"background_color": "#6366f1"
|
|
68
|
+
},
|
|
69
|
+
"features": {
|
|
70
|
+
"app_home": {
|
|
71
|
+
"messages_tab_enabled": true,
|
|
72
|
+
"messages_tab_read_only_enabled": false
|
|
73
|
+
},
|
|
74
|
+
"bot_user": {
|
|
75
|
+
"display_name": "AI Assistant",
|
|
76
|
+
"always_online": true
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"oauth_config": {
|
|
80
|
+
"redirect_urls": [
|
|
81
|
+
"https://api.your-app.com/api/slack/callback"
|
|
82
|
+
],
|
|
83
|
+
"scopes": {
|
|
84
|
+
"bot": [
|
|
85
|
+
"app_mentions:read",
|
|
86
|
+
"channels:history",
|
|
87
|
+
"groups:history",
|
|
88
|
+
"im:history",
|
|
89
|
+
"chat:write",
|
|
90
|
+
"reactions:write",
|
|
91
|
+
"users:read"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"settings": {
|
|
96
|
+
"event_subscriptions": {
|
|
97
|
+
"request_url": "https://api.your-app.com/api/slack/events",
|
|
98
|
+
"bot_events": [
|
|
99
|
+
"app_mention",
|
|
100
|
+
"message.channels",
|
|
101
|
+
"message.groups",
|
|
102
|
+
"message.im"
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
"org_deploy_enabled": false,
|
|
106
|
+
"socket_mode_enabled": false,
|
|
107
|
+
"token_rotation_enabled": false
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Note**: Replace `api.your-app.com` with your actual API domain (the value of `API_URL`). Both the `request_url` and `redirect_urls` must be publicly accessible.
|
|
113
|
+
|
|
114
|
+
## Configuration
|
|
115
|
+
|
|
116
|
+
### Environment Variables
|
|
117
|
+
|
|
118
|
+
Add these to your `.env` file:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
SLACK_CLIENT_ID=your-client-id
|
|
122
|
+
SLACK_CLIENT_SECRET=your-client-secret
|
|
123
|
+
SLACK_SIGNING_SECRET=your-signing-secret
|
|
124
|
+
SLACK_INTERNAL_SECRET=any-random-secret-for-internal-calls
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Generate the internal secret with:
|
|
128
|
+
```bash
|
|
129
|
+
openssl rand -hex 32
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### App Configuration
|
|
133
|
+
|
|
134
|
+
Enable Slack in your `config/app.config.ts`:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import type { AppConfig } from '@chaaskit/shared';
|
|
138
|
+
|
|
139
|
+
export const config: AppConfig = {
|
|
140
|
+
// ... other config
|
|
141
|
+
|
|
142
|
+
teams: {
|
|
143
|
+
enabled: true, // Required for Slack
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
slack: {
|
|
147
|
+
enabled: true,
|
|
148
|
+
clientIdEnvVar: 'SLACK_CLIENT_ID',
|
|
149
|
+
clientSecretEnvVar: 'SLACK_CLIENT_SECRET',
|
|
150
|
+
signingSecretEnvVar: 'SLACK_SIGNING_SECRET',
|
|
151
|
+
internalSecretEnvVar: 'SLACK_INTERNAL_SECRET',
|
|
152
|
+
|
|
153
|
+
// Optional: Restrict to specific plans
|
|
154
|
+
allowedPlans: ['pro', 'enterprise'],
|
|
155
|
+
|
|
156
|
+
// AI chat settings
|
|
157
|
+
aiChat: {
|
|
158
|
+
enabled: true,
|
|
159
|
+
threadContinuity: true, // Maintain context across Slack thread replies
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
// Team notifications
|
|
163
|
+
notifications: {
|
|
164
|
+
events: [
|
|
165
|
+
{ event: 'thread_shared', enabled: true },
|
|
166
|
+
{ event: 'message_liked', enabled: true },
|
|
167
|
+
{ event: 'team_member_joined', enabled: true },
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Connecting a Team
|
|
175
|
+
|
|
176
|
+
Once configured, team admins can connect Slack from the Team Settings page:
|
|
177
|
+
|
|
178
|
+
1. Go to Team Settings
|
|
179
|
+
2. Find the "Slack Integration" section
|
|
180
|
+
3. Click "Add to Slack"
|
|
181
|
+
4. Authorize the app in your Slack workspace
|
|
182
|
+
5. You'll be redirected back with a success message
|
|
183
|
+
|
|
184
|
+
## Using the Bot
|
|
185
|
+
|
|
186
|
+
### Basic Usage
|
|
187
|
+
|
|
188
|
+
Mention the bot in any channel:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
@YourBot What's the weather like today?
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The bot will:
|
|
195
|
+
1. Add an 👀 reaction to show it's processing
|
|
196
|
+
2. Generate a response using your AI agent
|
|
197
|
+
3. Reply in a thread
|
|
198
|
+
4. Replace the 👀 with ✅ when complete
|
|
199
|
+
|
|
200
|
+
**Note:** The bot only responds to messages that @mention it. Regular channel messages without an @mention are ignored.
|
|
201
|
+
|
|
202
|
+
### Thread Continuity
|
|
203
|
+
|
|
204
|
+
Once you've @mentioned the bot, you can continue the conversation in the thread **without** needing to @mention it again:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
User: @YourBot Explain quantum computing
|
|
208
|
+
Bot: Quantum computing uses quantum bits (qubits)...
|
|
209
|
+
|
|
210
|
+
User: Can you give me an example?
|
|
211
|
+
Bot: Sure! A classic example is Shor's algorithm...
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
The bot automatically responds to all messages in threads where it has been mentioned, maintaining context from the conversation.
|
|
215
|
+
|
|
216
|
+
### Response Formatting
|
|
217
|
+
|
|
218
|
+
The bot formats responses using Slack's mrkdwn syntax, so you'll see proper formatting for bold text, code blocks, lists, and links.
|
|
219
|
+
|
|
220
|
+
### Context from Your App
|
|
221
|
+
|
|
222
|
+
The bot uses the same AI agent and team context as your web app. If you've configured team context in Team Settings, it will be included in Slack conversations.
|
|
223
|
+
|
|
224
|
+
## Notifications
|
|
225
|
+
|
|
226
|
+
When enabled, your team's Slack channel will receive notifications for:
|
|
227
|
+
|
|
228
|
+
| Event | Notification |
|
|
229
|
+
|-------|--------------|
|
|
230
|
+
| Thread Shared | When a team member shares a conversation |
|
|
231
|
+
| Message Liked | When someone gives positive feedback on an AI response |
|
|
232
|
+
| Member Joined | When a new member joins the team |
|
|
233
|
+
|
|
234
|
+
### Configuring Notification Channel
|
|
235
|
+
|
|
236
|
+
1. Go to Team Settings → Slack Integration
|
|
237
|
+
2. Enter the notification channel (e.g., `#general`)
|
|
238
|
+
3. Click "Save Settings"
|
|
239
|
+
|
|
240
|
+
## Architecture
|
|
241
|
+
|
|
242
|
+
### Event Flow
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
1. User @mentions bot in Slack
|
|
246
|
+
2. Slack sends event to /api/slack/events
|
|
247
|
+
3. Server verifies signature, stores event, responds 200 OK (within 3s)
|
|
248
|
+
4. Server triggers /api/slack/internal/process asynchronously
|
|
249
|
+
5. Event processor:
|
|
250
|
+
- Fetches Slack thread history for context
|
|
251
|
+
- Finds/creates internal thread for continuity
|
|
252
|
+
- Calls AI agent with conversation
|
|
253
|
+
- Posts response back to Slack
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Data Storage
|
|
257
|
+
|
|
258
|
+
| Model | Purpose |
|
|
259
|
+
|-------|---------|
|
|
260
|
+
| `SlackIntegration` | Stores team's Slack connection (workspace ID, encrypted tokens, settings) |
|
|
261
|
+
| `SlackMessageEvent` | Tracks incoming events for deduplication and retry |
|
|
262
|
+
|
|
263
|
+
Tokens are encrypted at rest using AES-256-GCM.
|
|
264
|
+
|
|
265
|
+
### Retry Logic
|
|
266
|
+
|
|
267
|
+
Failed events are automatically retried:
|
|
268
|
+
- Events stuck in "pending" or "processing" for >3 minutes are retried
|
|
269
|
+
- Maximum 3 retry attempts per event
|
|
270
|
+
- Use `POST /api/slack/internal/retry` to trigger retry (requires internal secret)
|
|
271
|
+
|
|
272
|
+
## API Endpoints
|
|
273
|
+
|
|
274
|
+
| Endpoint | Method | Auth | Description |
|
|
275
|
+
|----------|--------|------|-------------|
|
|
276
|
+
| `/api/slack/install/:teamId` | GET | User (Admin) | Start OAuth flow |
|
|
277
|
+
| `/api/slack/callback` | GET | None | OAuth callback |
|
|
278
|
+
| `/api/slack/:teamId/status` | GET | User (Viewer+) | Get integration status |
|
|
279
|
+
| `/api/slack/:teamId/settings` | PATCH | User (Admin) | Update settings |
|
|
280
|
+
| `/api/slack/:teamId` | DELETE | User (Admin) | Disconnect Slack |
|
|
281
|
+
| `/api/slack/events` | POST | Slack Signature | Receive Slack events |
|
|
282
|
+
| `/api/slack/internal/process` | POST | Internal Secret | Process an event |
|
|
283
|
+
| `/api/slack/internal/retry` | POST | Internal Secret | Retry stale events |
|
|
284
|
+
|
|
285
|
+
## Troubleshooting
|
|
286
|
+
|
|
287
|
+
### Bot doesn't respond
|
|
288
|
+
|
|
289
|
+
1. Check that your Slack app has the required scopes
|
|
290
|
+
2. Verify Event Subscriptions URL is correct and verified
|
|
291
|
+
3. Check server logs for errors
|
|
292
|
+
4. Ensure the team has Slack connected (check Team Settings)
|
|
293
|
+
|
|
294
|
+
### "Invalid signature" errors
|
|
295
|
+
|
|
296
|
+
- Verify `SLACK_SIGNING_SECRET` matches your Slack app's signing secret
|
|
297
|
+
- Ensure raw request body is being used for signature verification
|
|
298
|
+
|
|
299
|
+
### Events timing out
|
|
300
|
+
|
|
301
|
+
Slack requires a response within 3 seconds. The integration handles this by:
|
|
302
|
+
1. Quickly acknowledging the event
|
|
303
|
+
2. Processing asynchronously via internal endpoint
|
|
304
|
+
|
|
305
|
+
If you see timeout errors, check that `/api/slack/internal/process` is accessible from your server.
|
|
306
|
+
|
|
307
|
+
### Thread context not working
|
|
308
|
+
|
|
309
|
+
- Ensure `threadContinuity` is enabled in config
|
|
310
|
+
- The bot needs `channels:history` (or equivalent) scope to read thread history
|
|
311
|
+
- Private channels require `groups:history`
|
|
312
|
+
|
|
313
|
+
## Security Considerations
|
|
314
|
+
|
|
315
|
+
- **Token Encryption**: Slack tokens are encrypted at rest using your `SESSION_SECRET`
|
|
316
|
+
- **Signature Verification**: All incoming Slack requests are verified using HMAC-SHA256
|
|
317
|
+
- **Internal Endpoints**: Protected by a separate secret to prevent external access
|
|
318
|
+
- **Scope Minimization**: Only request the Slack scopes you need
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Styling Guide
|
|
2
|
+
|
|
3
|
+
This guide documents the styling conventions used throughout the application to maintain visual consistency. Follow these patterns when building new pages and components.
|
|
4
|
+
|
|
5
|
+
## Design Principles
|
|
6
|
+
|
|
7
|
+
1. **Soft, not harsh**: Avoid hard borders and stark contrasts. Use subtle background colors for separation instead of explicit borders.
|
|
8
|
+
2. **Consistent spacing**: Use the same padding and margin patterns across similar components.
|
|
9
|
+
3. **Visual hierarchy**: Use typography and subtle color differences, not heavy borders, to establish hierarchy.
|
|
10
|
+
|
|
11
|
+
## Color Variables
|
|
12
|
+
|
|
13
|
+
Use CSS variables for all colors. Never hardcode color values.
|
|
14
|
+
|
|
15
|
+
### Primary Colors
|
|
16
|
+
|
|
17
|
+
| Variable | Usage |
|
|
18
|
+
|----------|-------|
|
|
19
|
+
| `--color-primary` | Primary actions, active states, links |
|
|
20
|
+
| `--color-primary-hover` | Hover state for primary elements |
|
|
21
|
+
| `--color-secondary` | Secondary accent color |
|
|
22
|
+
|
|
23
|
+
### Background Colors
|
|
24
|
+
|
|
25
|
+
| Variable | Usage |
|
|
26
|
+
|----------|-------|
|
|
27
|
+
| `--color-background` | Main page background |
|
|
28
|
+
| `--color-background-secondary` | Cards, sections, elevated surfaces |
|
|
29
|
+
| `--color-sidebar` | Sidebar background |
|
|
30
|
+
|
|
31
|
+
### Text Colors
|
|
32
|
+
|
|
33
|
+
| Variable | Usage |
|
|
34
|
+
|----------|-------|
|
|
35
|
+
| `--color-text-primary` | Main text, headings |
|
|
36
|
+
| `--color-text-secondary` | Body text, descriptions |
|
|
37
|
+
| `--color-text-muted` | Helper text, timestamps, placeholders |
|
|
38
|
+
|
|
39
|
+
### Input Colors
|
|
40
|
+
|
|
41
|
+
| Variable | Usage |
|
|
42
|
+
|----------|-------|
|
|
43
|
+
| `--color-input-background` | Input field backgrounds |
|
|
44
|
+
| `--color-input-border` | Input field borders (subtle) |
|
|
45
|
+
|
|
46
|
+
### Status Colors
|
|
47
|
+
|
|
48
|
+
| Variable | Usage |
|
|
49
|
+
|----------|-------|
|
|
50
|
+
| `--color-success` | Success messages, positive states |
|
|
51
|
+
| `--color-warning` | Warning messages, caution states |
|
|
52
|
+
| `--color-error` | Error messages, destructive actions |
|
|
53
|
+
|
|
54
|
+
## Section Styling
|
|
55
|
+
|
|
56
|
+
### Cards and Sections
|
|
57
|
+
|
|
58
|
+
**DO**: Use background colors for visual separation
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
// Good - Soft, borderless card
|
|
62
|
+
<div className="rounded-lg bg-[var(--color-background-secondary)] p-6">
|
|
63
|
+
<h2 className="text-lg font-semibold text-[var(--color-text-primary)] mb-4">
|
|
64
|
+
Section Title
|
|
65
|
+
</h2>
|
|
66
|
+
{/* content */}
|
|
67
|
+
</div>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**DON'T**: Use explicit borders for main sections
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// Bad - Harsh border
|
|
74
|
+
<div className="rounded-lg border border-[var(--color-border)] bg-[var(--color-background-secondary)] p-6">
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### List Items with Dividers
|
|
78
|
+
|
|
79
|
+
When items need visual separation, use the background color as a subtle divider:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
// Good - Subtle dividers using background color
|
|
83
|
+
<div className="divide-y divide-[var(--color-background)]">
|
|
84
|
+
{items.map(item => (
|
|
85
|
+
<div key={item.id} className="px-4 py-3">
|
|
86
|
+
{/* item content */}
|
|
87
|
+
</div>
|
|
88
|
+
))}
|
|
89
|
+
</div>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Table-like Lists
|
|
93
|
+
|
|
94
|
+
Use grid layouts with background-based headers instead of traditional bordered tables:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// Header
|
|
98
|
+
<div className="px-4 py-3 bg-[var(--color-background)]">
|
|
99
|
+
<div className="grid grid-cols-12 gap-4 text-sm font-medium text-[var(--color-text-muted)]">
|
|
100
|
+
<div className="col-span-3">Name</div>
|
|
101
|
+
<div className="col-span-2">Status</div>
|
|
102
|
+
{/* ... */}
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
// Body
|
|
107
|
+
<div className="divide-y divide-[var(--color-background)]">
|
|
108
|
+
{items.map(item => (
|
|
109
|
+
<div key={item.id} className="px-4 py-3 hover:bg-[var(--color-background)]/50">
|
|
110
|
+
<div className="grid grid-cols-12 gap-4 items-center">
|
|
111
|
+
{/* item content */}
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
))}
|
|
115
|
+
</div>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Button Styling
|
|
119
|
+
|
|
120
|
+
### Primary Buttons
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
<button className="rounded-lg bg-[var(--color-primary)] px-4 py-2 font-medium text-white hover:bg-[var(--color-primary-hover)]">
|
|
124
|
+
Save
|
|
125
|
+
</button>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Secondary Buttons (Soft)
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
// Good - Background-based, no border
|
|
132
|
+
<button className="rounded-lg bg-[var(--color-background-secondary)] px-4 py-2 text-[var(--color-text-primary)] hover:bg-[var(--color-background-secondary)]/80">
|
|
133
|
+
Cancel
|
|
134
|
+
</button>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
// Avoid - Bordered button
|
|
139
|
+
<button className="rounded-lg border border-[var(--color-border)] px-4 py-2">
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Text/Link Buttons
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
<button className="text-sm text-[var(--color-text-muted)] hover:text-[var(--color-text-primary)]">
|
|
146
|
+
Back to chat
|
|
147
|
+
</button>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Destructive Buttons
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
<button className="rounded-lg bg-[var(--color-error)] px-4 py-2 font-medium text-white hover:bg-[var(--color-error)]/90">
|
|
154
|
+
Delete
|
|
155
|
+
</button>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Form Inputs
|
|
159
|
+
|
|
160
|
+
Inputs should have subtle borders using the input-specific variables:
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
<input
|
|
164
|
+
type="text"
|
|
165
|
+
className="w-full rounded-lg border border-[var(--color-input-border)] bg-[var(--color-input-background)] px-4 py-2 text-[var(--color-text-primary)] placeholder-[var(--color-text-muted)] focus:border-[var(--color-primary)] focus:outline-none"
|
|
166
|
+
/>
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
For selects in compact contexts (like inline dropdowns):
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<select className="rounded border border-[var(--color-input-border)] bg-[var(--color-input-background)] px-2 py-1 text-sm text-[var(--color-text-primary)]">
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Pills and Badges
|
|
176
|
+
|
|
177
|
+
Use background colors with no borders:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
// Status badge
|
|
181
|
+
<span className="rounded-full bg-[var(--color-primary)]/10 px-2 py-0.5 text-xs font-medium text-[var(--color-primary)]">
|
|
182
|
+
Active
|
|
183
|
+
</span>
|
|
184
|
+
|
|
185
|
+
// Clickable pill
|
|
186
|
+
<Link className="inline-flex items-center rounded-full bg-[var(--color-background)] px-2 py-0.5 text-xs text-[var(--color-text-secondary)] hover:bg-[var(--color-primary)]/10 hover:text-[var(--color-primary)]">
|
|
187
|
+
Team Name
|
|
188
|
+
</Link>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Avatar Placeholders
|
|
192
|
+
|
|
193
|
+
When showing initials instead of an image, use the primary color:
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
<div className="w-8 h-8 rounded-full bg-primary flex items-center justify-center text-white text-sm font-medium">
|
|
197
|
+
{name[0].toUpperCase()}
|
|
198
|
+
</div>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Note: Use Tailwind's `bg-primary` class rather than `bg-[var(--color-primary)]` for avatars, as it's more reliable in some contexts.
|
|
202
|
+
|
|
203
|
+
## Page Layout
|
|
204
|
+
|
|
205
|
+
### Standard Admin/Settings Page
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
<div className="min-h-screen bg-[var(--color-background)] p-8">
|
|
209
|
+
<div className="mx-auto max-w-6xl">
|
|
210
|
+
{/* Header */}
|
|
211
|
+
<div className="flex items-center justify-between mb-8">
|
|
212
|
+
<h1 className="text-2xl font-bold text-[var(--color-text-primary)]">
|
|
213
|
+
Page Title
|
|
214
|
+
</h1>
|
|
215
|
+
<div className="flex gap-4">
|
|
216
|
+
{/* Navigation buttons */}
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
{/* Error/Success messages */}
|
|
221
|
+
{error && (
|
|
222
|
+
<div className="mb-6 rounded-lg bg-[var(--color-error)]/10 p-4 text-sm text-[var(--color-error)]">
|
|
223
|
+
{error}
|
|
224
|
+
</div>
|
|
225
|
+
)}
|
|
226
|
+
|
|
227
|
+
{/* Content sections */}
|
|
228
|
+
<div className="rounded-lg bg-[var(--color-background-secondary)] p-6 mb-6">
|
|
229
|
+
{/* Section content */}
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Hover States
|
|
236
|
+
|
|
237
|
+
Use subtle background changes for hover states:
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
// List item hover
|
|
241
|
+
className="hover:bg-[var(--color-background)]/50"
|
|
242
|
+
|
|
243
|
+
// Card hover (when clickable)
|
|
244
|
+
className="hover:bg-[var(--color-background-secondary)]/80"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Spacing Constants
|
|
248
|
+
|
|
249
|
+
| Use Case | Padding | Margin |
|
|
250
|
+
|----------|---------|--------|
|
|
251
|
+
| Page padding | `p-8` | - |
|
|
252
|
+
| Card/Section padding | `p-6` | `mb-6` or `mb-8` |
|
|
253
|
+
| List item padding | `px-4 py-3` | - |
|
|
254
|
+
| Compact item padding | `px-2 py-1` | - |
|
|
255
|
+
| Button padding | `px-4 py-2` | - |
|
|
256
|
+
| Badge padding | `px-2 py-0.5` | - |
|
|
257
|
+
|
|
258
|
+
## Reference Components
|
|
259
|
+
|
|
260
|
+
When building new UI, refer to these existing components for styling patterns:
|
|
261
|
+
|
|
262
|
+
| Component | Location | Good For |
|
|
263
|
+
|-----------|----------|----------|
|
|
264
|
+
| Settings Modal | `components/SettingsModal.tsx` | Modal dialogs, form layouts |
|
|
265
|
+
| Team Settings | `pages/TeamSettingsPage.tsx` | Full-page settings, member lists |
|
|
266
|
+
| Admin Dashboard | `pages/AdminDashboardPage.tsx` | Stats cards, charts, data display |
|
|
267
|
+
| Admin Users | `pages/AdminUsersPage.tsx` | Data tables, search, pagination |
|
|
268
|
+
| Sidebar | `components/Sidebar.tsx` | Navigation, lists, collapsible sections |
|
|
269
|
+
|
|
270
|
+
## Anti-Patterns to Avoid
|
|
271
|
+
|
|
272
|
+
1. **Explicit borders on cards**: Use `bg-background-secondary` instead of `border border-[var(--color-border)]`
|
|
273
|
+
|
|
274
|
+
2. **Dark/harsh dividers**: Use `divide-[var(--color-background)]` instead of `divide-[var(--color-border)]`
|
|
275
|
+
|
|
276
|
+
3. **Bordered buttons**: Use background colors for secondary buttons
|
|
277
|
+
|
|
278
|
+
4. **CSS variable syntax for avatars**: Use Tailwind classes like `bg-primary` for avatar backgrounds
|
|
279
|
+
|
|
280
|
+
5. **Inconsistent spacing**: Follow the spacing constants above
|
|
281
|
+
|
|
282
|
+
6. **Hardcoded colors**: Always use CSS variables
|
|
283
|
+
|
|
284
|
+
## Tailwind vs CSS Variables
|
|
285
|
+
|
|
286
|
+
- **Use Tailwind classes** (`bg-primary`, `text-text-primary`) when available and working correctly
|
|
287
|
+
- **Use CSS variables** (`bg-[var(--color-primary)]`) when Tailwind classes don't resolve properly or for complex color manipulation
|
|
288
|
+
- **For avatars specifically**, prefer Tailwind classes as they're more reliable
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>{{APP_NAME}}</title>
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|