Compare commits

..

2 Commits

Author SHA1 Message Date
Kunthawat Greethong
705608ae46 Add Dyad Update Management Guide and custom hooks for smart context
Some checks failed
CI / test (map[image:macos-latest name:macos], 1, 4) (push) Has been cancelled
CI / test (map[image:macos-latest name:macos], 2, 4) (push) Has been cancelled
CI / test (map[image:macos-latest name:macos], 3, 4) (push) Has been cancelled
CI / test (map[image:macos-latest name:macos], 4, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 1, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 2, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 3, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 4, 4) (push) Has been cancelled
CI / merge-reports (push) Has been cancelled
2025-12-05 20:01:06 +07:00
Kunthawat Greethong
73fc42bf4f Add custom code structure and update scripts
Some checks failed
CI / test (map[image:macos-latest name:macos], 1, 4) (push) Has been cancelled
CI / test (map[image:macos-latest name:macos], 2, 4) (push) Has been cancelled
CI / test (map[image:macos-latest name:macos], 3, 4) (push) Has been cancelled
CI / test (map[image:macos-latest name:macos], 4, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 1, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 2, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 3, 4) (push) Has been cancelled
CI / test (map[image:windows-latest name:windows], 4, 4) (push) Has been cancelled
CI / merge-reports (push) Has been cancelled
- Organized custom modifications in src/custom/
- Added update-dyad-v2.sh for selective updates
- Preserved custom smart context functionality
- Created backup system for safe updates
2025-12-05 19:57:45 +07:00
305 changed files with 5402 additions and 15939 deletions

View File

@@ -107,10 +107,6 @@ jobs:
# Merge reports after playwright-tests, even if some shards have failed
if: ${{ !cancelled() }}
needs: [test]
permissions:
contents: read
pull-requests: write
actions: read
runs-on: ubuntu-latest
steps:

View File

@@ -1,59 +0,0 @@
name: Playwright Report Comment
on:
workflow_run:
workflows: ["CI"]
types:
- completed
permissions:
contents: read
pull-requests: write
issues: write
actions: read
jobs:
comment:
if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.pull_requests[0].number }}
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.base_ref }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Download Playwright HTML report
uses: actions/download-artifact@v4
with:
name: html-report--attempt-${{ github.event.workflow_run.run_attempt }}
path: playwright-report
github-token: ${{ github.token }}
repository: ${{ github.event.workflow_run.repository.full_name }}
run-id: ${{ github.event.workflow_run.id }}
if-no-artifact-found: warn
- name: Download blob reports
uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
github-token: ${{ github.token }}
repository: ${{ github.event.workflow_run.repository.full_name }}
run-id: ${{ github.event.workflow_run.id }}
if-no-artifact-found: warn
- name: Generate Playwright summary comment
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
PLAYWRIGHT_RUN_ID: ${{ github.event.workflow_run.id }}
with:
script: |
const { run } = require('./scripts/generate-playwright-summary.js');
await run({ github, context, core });

View File

@@ -21,7 +21,7 @@ jobs:
{ name: "windows", image: "windows-latest" },
# See https://github.com/dyad-sh/dyad/issues/96
{ name: "linux", image: "ubuntu-22.04" },
{ name: "macos-intel", image: "macos-15-intel" },
{ name: "macos-intel", image: "macos-13" },
{ name: "macos", image: "macos-latest" },
]
runs-on: ${{ matrix.os.image }}

587
README.md
View File

@@ -1,589 +1,34 @@
# MoreMinimore
# Dyad
MoreMinimore is a local, open-source AI app builder. It's fast, private, and fully under your control — like Lovable, v0, or Bolt, but running right on your machine.
Dyad is a local, open-source AI app builder. It's fast, private, and fully under your control — like Lovable, v0, or Bolt, but running right on your machine.
![Image](https://github.com/user-attachments/assets/f6c83dfc-6ffd-4d32-93dd-4b9c46d17790)
[![Image](https://github.com/user-attachments/assets/f6c83dfc-6ffd-4d32-93dd-4b9c46d17790)](https://dyad.sh/)
More info at: [https://dyad.sh/](https://dyad.sh/)
## 🚀 Features
- ⚡️ **Local**: Fast, private and no lock-in.
- 🛠 **Bring your own keys**: Use your own AI API keys — no vendor lock-in.
- 🖥️ **Cross-platform**: Easy to run on Mac or Windows.
-**Enhanced**: Smart context and unlimited usage with custom features.
- 🎯 **No limitations**: All Pro features available to everyone.
- 🔒 **Privacy-focused**: No external API calls to commercial services.
## 🧰 Prerequisites
## 📦 Download
- Node.js >= 20
- npm (comes with Node.js)
- Git
No sign-up required. Just download and go.
You can verify your versions:
### [👉 Download for your platform](https://www.dyad.sh/#download)
```bash
node -v
npm -v
```
## 🤝 Community
## 🚀 Quick Start
Join our growing community of AI app builders on **Reddit**: [r/dyadbuilders](https://www.reddit.com/r/dyadbuilders/) - share your projects and get help from the community!
### Option 1: Download and Run (Easiest)
## 🛠️ Contributing
1. **Download the latest release** from [GitHub Releases](https://github.com/kunthawat/moreminimore-vibe/releases)
2. **Install the application** for your platform
3. **Launch MoreMinimore** and start building!
**Dyad** is open-source (Apache 2.0 licensed).
### Option 2: Build from Source
If you're interested in contributing to dyad, please read our [contributing](./CONTRIBUTING.md) doc.
```bash
# Clone the repository
git clone https://github.com/kunthawat/moreminimore-vibe.git
cd moreminimore-vibe
## License
# Install dependencies
npm install
# Apply custom features and debranding
chmod +x scripts/update-and-debrand.sh
./scripts/update-and-debrand.sh
# Start the application
npm start
```
## 📋 Essential Commands
This section contains all the commands you'll frequently need. Copy and paste these directly.
### 🏗️ Development Commands
```bash
# Start development server
npm start
# Check TypeScript compilation
npm run ts
# Run tests
npm test
# Run linting
npm run lint
# Format code
npm run prettier
# Clean build artifacts
npm run clean
```
### 🔨 Build Commands
```bash
# Development build (no code signing)
./scripts/build-moreminimore-app.sh
# Production build (requires code signing setup)
./scripts/build-moreminimore-app.sh --production
# Clean build artifacts only
./scripts/build-moreminimore-app.sh --clean-only
# Verbose build (for debugging)
./scripts/build-moreminimore-app.sh --verbose
# Fast build (skip dependency install)
./scripts/build-moreminimore-app.sh --skip-deps
# Create distributables
npm run make
```
### 🔄 Update Commands
```bash
# Apply custom features and debranding
./scripts/update-and-debrand.sh
# Integrate custom features after upstream update
./scripts/integrate-custom-features.sh integrate
# Validate custom features integration
./scripts/integrate-custom-features.sh validate
# Restore from backup (if needed)
./scripts/integrate-custom-features.sh restore backup-YYYYMMDD-HHMMSS
```
### 🧪 Testing Commands
```bash
# Run unit tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with UI
npm run test:ui
# Run end-to-end tests
npm run e2e
# Run E2E tests with sharding
npm run e2e:shard
```
## 🏗️ Complete Setup Guide
### Step 1: Clone and Install
```bash
# Clone the repository
git clone https://github.com/kunthawat/moreminimore-vibe.git
cd moreminimore-vibe
# Install dependencies
npm install
# Make scripts executable
chmod +x scripts/*.sh
```
### Step 2: Apply Custom Features
```bash
# Run the debranding and custom features script
./scripts/update-and-debrand.sh
```
This script will:
- ✅ Create automatic backup
- ✅ Apply remove-limit feature
- ✅ Enable smart context for all users
- ✅ Remove Dyad branding and dependencies
- ✅ Update all branding to MoreMinimore
- ✅ Install dependencies and test compilation
### Step 3: Verify Installation
```bash
# Check TypeScript compilation
npm run ts
# Start the application
npm start
```
### Step 4: Test Build (Optional)
```bash
# Test build process
./scripts/build-moreminimore-app.sh
```
## 📦 Building for Distribution
### Development Build (Recommended for Testing)
```bash
./scripts/build-moreminimore-app.sh
```
- **Output**: `out/make/zip/darwin/arm64/moreminimore-darwin-arm64-*.zip`
- **Size**: ~180MB
- **Code Signing**: Disabled (for development/testing)
### Production Build (Requires Code Signing)
```bash
# Set up Apple Developer credentials first
export APPLE_TEAM_ID="your-apple-developer-team-id"
export APPLE_ID="your-apple-id@example.com"
export APPLE_PASSWORD="your-app-specific-password"
export SM_CODE_SIGNING_CERT_SHA1_HASH="your-certificate-sha1-hash"
# Build production version
./scripts/build-moreminimore-app.sh --production
```
### Build Options
```bash
# Clean build artifacts only
./scripts/build-moreminimore-app.sh --clean-only
# Verbose output for debugging
./scripts/build-moreminimore-app.sh --verbose
# Skip dependency installation
./scripts/build-moreminimore-app.sh --skip-deps
# Show help
./scripts/build-moreminimore-app.sh --help
```
## 🔄 Updating from Upstream
When you want to update MoreMinimore with new features from the original Dyad repository:
### Step 1: Fetch Latest Changes
```bash
# Add upstream remote (if not already added)
git remote add upstream https://github.com/dyad-sh/dyad.git
# Fetch latest changes
git fetch upstream
# Merge upstream changes
git merge upstream/main
```
### Step 2: Re-apply Custom Features
```bash
# Run the update script to re-apply all customizations
./scripts/update-and-debrand.sh
```
### Step 3: Integrate Custom Features
```bash
# Integrate custom features with the new codebase
./scripts/integrate-custom-features.sh integrate
# Validate the integration
./scripts/integrate-custom-features.sh validate
```
### Step 4: Test and Commit
```bash
# Test the application
npm start
# Test build process
./scripts/build-moreminimore-app.sh
# Commit changes if everything works
git add .
git commit -m "Update upstream and re-apply custom features"
```
## 🛠️ Custom Features
### Remove-Limit Feature
- **Unlimited usage**: No message limits or restrictions
- **Full feature access**: All Pro features available to everyone
- **No upgrade prompts**: Clean interface without commercial restrictions
### Smart Context for All Users
- **Advanced context management**: Intelligent handling of long conversations
- **Rolling summaries**: Automatic summarization when context exceeds thresholds
- **Context caching**: Efficient caching with TTL for better performance
- **Snippet importance scoring**: Intelligent ranking of context snippets
### Enhanced UI/UX
- **Clean interface**: No Pro banners or upgrade buttons
- **Improved branding**: Complete MoreMinimore branding throughout
- **Better organization**: Simplified controls and settings
- **Context Settings**: Improved UI for context management
## 🔧 Configuration
### Environment Variables (Optional)
```bash
# Set custom gateway URL
MOREMINIMORE_GATEWAY_URL=http://localhost:8080/v1 npm start
# Development mode with debugging
DEBUG=* npm start
# Production mode
NODE_ENV=production npm start
```
### Custom Feature Flags
Edit `src/custom/index.ts` to enable/disable features:
```typescript
export const REMOVE_LIMIT_ENABLED = true;
export const SMART_CONTEXT_ENABLED = true;
export const ANNOTATOR_ENABLED = true;
```
## 🐛 Troubleshooting
### Common Issues and Solutions
#### TypeScript Compilation Errors
```bash
# Check TypeScript compilation
npm run ts
# If errors occur, check specific files
npm run ts:main # Main process
npm run ts:workers # Worker processes
```
#### Application Won't Start
```bash
# Check dependencies
npm install
# Clean and rebuild
npm run clean
npm install
npm start
# Check logs for specific errors
npm start 2>&1 | tee startup-errors.log
```
#### Build Issues
```bash
# Clean build artifacts
./scripts/build-moreminimore-app.sh --clean-only
# Verbose build for debugging
./scripts/build-moreminimore-app.sh --verbose
# Check Node.js and npm versions
node -v
npm -v
```
#### Script Permission Issues
```bash
# Make scripts executable
chmod +x scripts/*.sh
# Check script permissions
ls -la scripts/
```
#### Integration Issues After Update
```bash
# Validate current integration
./scripts/integrate-custom-features.sh validate
# Restore from backup if needed
ls backups/ # Find latest backup
./scripts/integrate-custom-features.sh restore backup-YYYYMMDD-HHMMSS
# Re-run integration
./scripts/integrate-custom-features.sh integrate
```
### Recovery Procedures
#### Restore from Backup
```bash
# Find available backups
ls -la backups/
# Restore from specific backup
./scripts/integrate-custom-features.sh restore backup-20231218-154512
# Verify restoration
./scripts/integrate-custom-features.sh validate
```
#### Reset to Clean State
```bash
# Clean all build artifacts
npm run clean
rm -rf node_modules package-lock.json
# Reinstall dependencies
npm install
# Re-apply custom features
./scripts/update-and-debrand.sh
```
## 📁 Project Structure
### Important Files and Directories
```
moreminimore-vibe/
├── src/ # Source code
│ ├── components/ # React components
│ ├── ipc/ # IPC handlers and utilities
│ ├── pages/ # Application pages
│ └── custom/ # Custom feature flags
├── scripts/ # Build and utility scripts
│ ├── update-and-debrand.sh # Main debranding script
│ ├── build-moreminimore-app.sh # Build automation
│ └── integrate-custom-features.sh # Feature integration
├── assets/ # Static assets (logos, icons)
├── out/ # Build output directory
└── backups/ # Automatic backups (created as needed)
```
### Key Scripts
- **`scripts/update-and-debrand.sh`** - Applies all custom features and debranding
- **`scripts/build-moreminimore-app.sh`** - Comprehensive build automation
- **`scripts/integrate-custom-features.sh`** - Manages custom feature integration
### Configuration Files
- **`package.json`** - Project configuration and dependencies
- **`src/custom/index.ts`** - Custom feature flags
- **`forge.config.ts`** - Electron Forge configuration
## 🎯 Development Workflow
### Daily Development
```bash
# 1. Start development server
npm start
# 2. Make changes to code
# 3. Check TypeScript compilation
npm run ts
# 4. Run tests
npm test
# 5. Format code
npm run prettier
# 6. Test build
./scripts/build-moreminimore-app.sh
```
### Before Committing
```bash
# Run all checks
npm run presubmit
# Or run individually
npm run prettier:check
npm run lint
npm run ts
npm test
```
### Release Preparation
```bash
# 1. Update version in package.json
# 2. Test thoroughly
npm test
./scripts/build-moreminimore-app.sh
# 3. Create production build
./scripts/build-moreminimore-app.sh --production
# 4. Verify release assets
npm run verify-release
```
## 📚 Advanced Topics
### Code Signing Setup
For production builds, set up Apple Developer credentials:
```bash
# Set environment variables
export APPLE_TEAM_ID="your-apple-developer-team-id"
export APPLE_ID="your-apple-id@example.com"
export APPLE_PASSWORD="your-app-specific-password"
export SM_CODE_SIGNING_CERT_SHA1_HASH="your-certificate-sha1-hash"
# Find your Team ID
security find-identity -v -p codesigning
# Generate app-specific password
# Visit: https://appleid.apple.com → Security → App-Specific Passwords
```
### Custom Feature Development
1. **Add feature flag** to `src/custom/index.ts`
2. **Implement feature** in appropriate files
3. **Update scripts** to apply changes automatically
4. **Test thoroughly** with `npm test` and `npm run ts`
### Database Operations
```bash
# Generate database migrations
npm run db:generate
# Push database changes
npm run db:push
# Open database studio
npm run db:studio
```
## 🤝 Contributing
1. **Fork the repository**
2. **Create a feature branch**: `git checkout -b feature-name`
3. **Make your changes**
4. **Run tests**: `npm test`
5. **Check formatting**: `npm run prettier:check`
6. **Commit changes**: `git commit -m "Add feature description"`
7. **Push to fork**: `git push origin feature-name`
8. **Create Pull Request**
### Contribution Guidelines
- Ensure no Dyad dependencies are added
- Maintain custom features and branding
- Update documentation as needed
- Test thoroughly before submitting
- Follow existing code style and patterns
## 📄 License
MIT License — see [LICENSE](./LICENSE).
## 🔗 Related Resources
- **GitHub Repository**: https://github.com/kunthawat/moreminimore-vibe
- **Issues and Bug Reports**: https://github.com/kunthawat/moreminimore-vibe/issues
- **Community**: Join our growing community of AI app builders
## 🆘 Support
If you encounter issues:
1. **Check this README** for troubleshooting steps
2. **Review the logs** with `--verbose` flag on scripts
3. **Search existing issues** on GitHub
4. **Create a new issue** with detailed information
5. **Test with clean environment** if needed
### Getting Help
For specific issues:
- **Build problems**: Run `./scripts/build-moreminimore-app.sh --verbose`
- **Integration issues**: Run `./scripts/integrate-custom-features.sh validate`
- **Application crashes**: Check console logs and `startup-errors.log`
- **TypeScript errors**: Run `npm run ts` for specific error details
---
**MoreMinimore** is a fork of [Dyad](https://github.com/dyad-sh/dyad) with enhanced features, removed limitations, and complete independence from commercial services. Enjoy building AI applications with full control and no restrictions!
- All the code in this repo outside of `src/pro` is open-source and licensed under Apache 2.0 - see [LICENSE](./LICENSE).
- All the code in this repo within `src/pro` is fair-source and licensed under [Functional Source License 1.1 Apache 2.0](https://fsl.software/) - see [LICENSE](./src/pro/LICENSE).

View File

@@ -6,4 +6,4 @@ We will provide security fixes for the latest version of Dyad and encourage Dyad
## Reporting a Vulnerability
Please file security vulnerabilities by using [report a vulnerability](https://github.com/kunthawat/moreminimore-vibe/security/advisories/new). Please do not file security vulnerabilities as a regular issue as the information could be used to exploit Dyad users.
Please file security vulnerabilities by using [report a vulnerability](https://github.com/dyad-sh/dyad/security/advisories/new). Please do not file security vulnerabilities as a regular issue as the information could be used to exploit Dyad users.

198
UPDATE_GUIDE.md Normal file
View File

@@ -0,0 +1,198 @@
# Dyad Update Management Guide
This guide explains how to update your forked Dyad application while preserving your custom modifications.
## 🎯 Overview
Your setup uses a **selective update strategy** that:
- Keeps your custom code separate from the main codebase
- Automatically preserves custom modifications during updates
- Provides backup and rollback capabilities
- Minimizes merge conflicts
## 📁 Custom Code Structure
Your custom modifications are organized in `src/custom/`:
```
src/custom/
├── index.ts # Main entry point for custom features
├── hooks/
│ └── useSmartContext.ts # Custom smart context hook
├── ipc/
│ └── smart_context_handlers.ts # Custom IPC handlers
└── utils/
└── smart_context_store.ts # Custom utilities
```
## 🚀 Update Process
### Method 1: Automated Update (Recommended)
Use the provided update script:
```bash
./update-dyad-v2.sh
```
**What the script does:**
1. Creates a timestamped backup
2. Backs up your custom code
3. Fetches latest changes from upstream
4. Resets to the latest upstream version
5. Restores your custom code
6. Pushes updates to your fork
### Method 2: Manual Update
If you prefer manual control:
```bash
# 1. Create backup
cp -r src/custom/ dyad-backup-$(date +%Y%m%d-%H%M%S)/
# 2. Fetch latest changes
git fetch upstream
# 3. Reset to latest upstream
git reset --hard upstream/main
# 4. Restore custom code
cp -r dyad-backup-*/src/custom/ src/
# 5. Commit and push
git add src/custom/
git commit -m "Restore custom code after update"
git push origin main
```
## 🔄 Update Workflow
### Before Updating
1. **Test current state** - Ensure your app works properly
2. **Commit any changes** - Don't have uncommitted work
3. **Check custom code** - Note any modifications that might need updates
### After Updating
1. **Run npm install** - Update dependencies if needed
2. **Test the application** - Ensure everything works
3. **Check custom integrations** - Verify custom features still work
4. **Update custom code** if needed - Adapt to any API changes
## 🛠️ Adding New Custom Features
When adding new custom features:
1. **Place in src/custom/** - Keep custom code organized
2. **Update imports** - Use relative imports within custom directory
3. **Document changes** - Note what each custom feature does
4. **Test integration** - Ensure custom features work with main app
Example:
```typescript
// src/custom/components/MyCustomComponent.tsx
import { useSmartContext } from '../hooks/useSmartContext';
export const MyCustomComponent = () => {
// Your custom logic
};
```
## 🚨 Troubleshooting
### Merge Conflicts
If you encounter merge conflicts during manual updates:
```bash
# Abort the merge
git merge --abort
# Use the automated script instead
./update-dyad-v2.sh
```
### Custom Code Not Working
After an update, if custom features don't work:
1. **Check API changes** - The upstream may have changed interfaces
2. **Update imports** - File paths might have changed
3. **Review breaking changes** - Check upstream release notes
4. **Test incrementally** - Isolate the problematic code
### Backup Restoration
If you need to restore from backup:
```bash
# Find your backup directory
ls dyad-backup-*
# Restore specific files
cp -r dyad-backup-YYYYMMDD-HHMMSS/src/custom/ src/
# Or restore entire project (last resort)
rm -rf * .gitignore
cp -r dyad-backup-YYYYMMDD-HHMMSS/* .
cp dyad-backup-YYYYMMDD-HHMMSS/.gitignore .
```
## 📋 Best Practices
### Regular Maintenance
- **Update frequently** - Smaller updates are easier to manage
- **Test after each update** - Catch issues early
- **Keep custom code minimal** - Only customize what's necessary
- **Document customizations** - Future you will thank you
### Code Organization
- **Separate concerns** - Keep UI, logic, and utilities separate
- **Use TypeScript** - Catch integration issues early
- **Follow existing patterns** - Match the upstream code style
- **Avoid modifying core files** - Use extension patterns when possible
### Backup Strategy
- **Multiple backups** - Keep several backup versions
- **Offsite backup** - Consider cloud storage for critical backups
- **Test backups** - Ensure you can restore from backup
- **Label clearly** - Use descriptive backup names
## 🔧 Advanced Configuration
### Custom Update Script
You can modify `update-dyad-v2.sh` to:
- Skip certain files from backup
- Add custom post-update steps
- Include additional validation
- Send notifications on completion
### Selective File Restoration
To restore only specific custom files:
```bash
# Restore specific directory
cp -r dyad-backup-*/src/custom/hooks/ src/custom/
# Restore specific file
cp dyad-backup-*/src/custom/index.ts src/custom/
```
## 📞 Getting Help
If you encounter issues:
1. **Check this guide first** - Most common issues are covered
2. **Review the script output** - Error messages are informative
3. **Test with a clean state** - Start fresh if needed
4. **Document the issue** - Note what you were trying to do
## 🎉 Success Indicators
You'll know the update was successful when:
- ✅ Script completes without errors
- ✅ Custom code is present in `src/custom/`
- ✅ Application starts and runs normally
- ✅ Custom features work as expected
- ✅ No merge conflicts in git status
---
**Remember**: The goal is to make updates painless and predictable. When in doubt, use the automated script and keep good backups!

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -14,9 +14,9 @@ If you're not familiar with Electron apps, they are similar to a full-stack Java
The core workflow of Dyad is that a user sends a prompt to the AI which edits the code and is reflected in the preview. We'll break this down step-by-step.
1. **Constructing an LLM request** - the LLM request that Dyad sends consists of much more than the prompt (i.e. user input). It includes, by default, the entire codebase as well as a detailed [system prompt](https://github.com/kunthawat/moreminimore-vibe/blob/main/src/prompts/system_prompt.ts) which gives the LLM instructions to respond in a specific XML-like format (e.g. `<dyad-write path="path/to/file.ts">console.log("hi")</dyad-write>`).
2. **Stream the LLM response to the UI** - It's important to provide visual feedback to the user otherwise they're waiting for several minutes without knowing what's happening so we stream the LLM response and show the LLM response. We have a specialized [Markdown parser](https://github.com/kunthawat/moreminimore-vibe/blob/main/src/components/chat/DyadMarkdownParser.tsx) which parses these `<dyad-*>` tags like the `<dyad-write>` tag shown earlier, so we can display the LLM output in a nice UI rather than just printing out raw XML-like text.
3. **Process the LLM response** - Once the LLM response has finished, and the user has approved the changes, the [response processor](https://github.com/kunthawat/moreminimore-vibe/blob/main/src/ipc/processors/response_processor.ts) in the main process applies these changes. Essentially each `<dyad-*>` tag described in the [system prompt](https://github.com/kunthawat/moreminimore-vibe/blob/main/src/prompts/system_prompt.ts) maps to specific logic in the response processor, e.g. writing a file, deleting a file, adding a new NPM package, etc.
1. **Constructing an LLM request** - the LLM request that Dyad sends consists of much more than the prompt (i.e. user input). It includes, by default, the entire codebase as well as a detailed [system prompt](https://github.com/dyad-sh/dyad/blob/main/src/prompts/system_prompt.ts) which gives the LLM instructions to respond in a specific XML-like format (e.g. `<dyad-write path="path/to/file.ts">console.log("hi")</dyad-write>`).
2. **Stream the LLM response to the UI** - It's important to provide visual feedback to the user otherwise they're waiting for several minutes without knowing what's happening so we stream the LLM response and show the LLM response. We have a specialized [Markdown parser](https://github.com/dyad-sh/dyad/blob/main/src/components/chat/DyadMarkdownParser.tsx) which parses these `<dyad-*>` tags like the `<dyad-write>` tag shown earlier, so we can display the LLM output in a nice UI rather than just printing out raw XML-like text.
3. **Process the LLM response** - Once the LLM response has finished, and the user has approved the changes, the [response processor](https://github.com/dyad-sh/dyad/blob/main/src/ipc/processors/response_processor.ts) in the main process applies these changes. Essentially each `<dyad-*>` tag described in the [system prompt](https://github.com/dyad-sh/dyad/blob/main/src/prompts/system_prompt.ts) maps to specific logic in the response processor, e.g. writing a file, deleting a file, adding a new NPM package, etc.
To recap, Dyad essentially tells the LLM about a bunch of tools like writing files using the `<dyad-*>` tags, the renderer process displays these Dyad tags in a nice UI and the main process executes these Dyad tags to apply the changes.

View File

@@ -765,4 +765,3 @@
"indexes": {}
}
}

View File

@@ -0,0 +1,7 @@
52a977b backup: auto-commit before update - Fri Dec 5 15:16:35 +07 2025
8a1cecb backup: auto-commit before update - Fri Dec 5 15:12:17 +07 2025
e6de49c fix: update .gitignore to exclude 'out/' directory
6d74721 Add user settings configuration for GPT-5 Codex model with Azure provider
d22227b feat: implement fuzzy search and replace functionality with Levenshtein distance
11986a0 Add project files
3b43cb5 Add blank

View File

@@ -0,0 +1,60 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { IpcClient } from "@/ipc/ipc_client";
import type {
SmartContextMeta,
SmartContextSnippet,
SmartContextRetrieveResult,
} from "@/ipc/ipc_types";
export function useSmartContextMeta(chatId: number) {
return useQuery<SmartContextMeta, Error>({
queryKey: ["smart-context", chatId, "meta"],
queryFn: async () => {
const ipc = IpcClient.getInstance();
return ipc.getSmartContextMeta(chatId);
},
enabled: !!chatId,
});
}
export function useRetrieveSmartContext(
chatId: number,
query: string,
budgetTokens: number,
) {
return useQuery<SmartContextRetrieveResult, Error>({
queryKey: ["smart-context", chatId, "retrieve", query, budgetTokens],
queryFn: async () => {
const ipc = IpcClient.getInstance();
return ipc.retrieveSmartContext({ chatId, query, budgetTokens });
},
enabled: !!chatId && !!query && budgetTokens > 0,
meta: { showErrorToast: true },
});
}
export function useUpsertSmartContextSnippets(chatId: number) {
const qc = useQueryClient();
return useMutation<number, Error, Array<Pick<SmartContextSnippet, "text" | "source">>>({
mutationFn: async (snippets) => {
const ipc = IpcClient.getInstance();
return ipc.upsertSmartContextSnippets(chatId, snippets);
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["smart-context", chatId] });
},
});
}
export function useUpdateRollingSummary(chatId: number) {
const qc = useQueryClient();
return useMutation<SmartContextMeta, Error, { summary: string }>({
mutationFn: async ({ summary }) => {
const ipc = IpcClient.getInstance();
return ipc.updateSmartContextRollingSummary(chatId, summary);
},
onSuccess: () => {
qc.invalidateQueries({ queryKey: ["smart-context", chatId, "meta"] });
},
});
}

View File

@@ -0,0 +1,18 @@
// Custom modules for moreminimore-vibe
// This file exports all custom functionality to make imports easier
// Custom hooks
export { useSmartContextMeta, useRetrieveSmartContext, useUpsertSmartContextSnippets, useUpdateRollingSummary } from './hooks/useSmartContext';
// Custom IPC handlers (these will need to be imported and registered in the main process)
export { registerSmartContextHandlers } from './ipc/smart_context_handlers';
// Custom utilities
export * from './utils/smart_context_store';
// Re-export types that might be needed
export type {
SmartContextMeta,
SmartContextSnippet,
SmartContextRetrieveResult,
} from '../ipc/ipc_types';

View File

@@ -0,0 +1,65 @@
import log from "electron-log";
import { createLoggedHandler } from "./safe_handle";
import {
appendSnippets,
readMeta,
retrieveContext,
updateRollingSummary,
rebuildIndex,
type SmartContextSnippet,
type SmartContextMeta,
} from "../utils/smart_context_store";
const logger = log.scope("smart_context_handlers");
const handle = createLoggedHandler(logger);
export interface UpsertSnippetsParams {
chatId: number;
snippets: Array<{
text: string;
source:
| { type: "message"; messageIndex?: number }
| { type: "code"; filePath: string }
| { type: "attachment"; name: string; mime?: string }
| { type: "other"; label?: string };
}>;
}
export interface RetrieveContextParams {
chatId: number;
query: string;
budgetTokens: number;
}
export function registerSmartContextHandlers() {
handle("sc:get-meta", async (_event, chatId: number): Promise<SmartContextMeta> => {
return readMeta(chatId);
});
handle(
"sc:upsert-snippets",
async (_event, params: UpsertSnippetsParams): Promise<number> => {
const count = await appendSnippets(params.chatId, params.snippets);
return count;
},
);
handle(
"sc:update-rolling-summary",
async (_event, params: { chatId: number; summary: string }): Promise<SmartContextMeta> => {
return updateRollingSummary(params.chatId, params.summary);
},
);
handle(
"sc:retrieve-context",
async (_event, params: RetrieveContextParams) => {
return retrieveContext(params.chatId, params.query, params.budgetTokens);
},
);
handle("sc:rebuild-index", async (_event, chatId: number) => {
await rebuildIndex(chatId);
return { ok: true } as const;
});
}

View File

@@ -0,0 +1,212 @@
import path from "node:path";
import { promises as fs } from "node:fs";
import { randomUUID } from "node:crypto";
import { getUserDataPath } from "../../paths/paths";
import { estimateTokens } from "./token_utils";
export type SmartContextSource =
| { type: "message"; messageIndex?: number }
| { type: "code"; filePath: string }
| { type: "attachment"; name: string; mime?: string }
| { type: "other"; label?: string };
export interface SmartContextSnippet {
id: string;
text: string;
score?: number;
source: SmartContextSource;
ts: number; // epoch ms
tokens?: number;
}
export interface SmartContextMetaConfig {
maxSnippets?: number;
}
export interface SmartContextMeta {
entityId: string; // e.g., chatId as string
updatedAt: number;
rollingSummary?: string;
summaryTokens?: number;
config?: SmartContextMetaConfig;
}
function getThreadDir(chatId: number): string {
const base = path.join(getUserDataPath(), "smart-context", "threads");
return path.join(base, String(chatId));
}
function getMetaPath(chatId: number): string {
return path.join(getThreadDir(chatId), "meta.json");
}
function getSnippetsPath(chatId: number): string {
return path.join(getThreadDir(chatId), "snippets.jsonl");
}
async function ensureDir(dir: string): Promise<void> {
await fs.mkdir(dir, { recursive: true });
}
export async function readMeta(chatId: number): Promise<SmartContextMeta> {
const dir = getThreadDir(chatId);
await ensureDir(dir);
const metaPath = getMetaPath(chatId);
try {
const raw = await fs.readFile(metaPath, "utf8");
const meta = JSON.parse(raw) as SmartContextMeta;
return meta;
} catch {
const fresh: SmartContextMeta = {
entityId: String(chatId),
updatedAt: Date.now(),
rollingSummary: "",
summaryTokens: 0,
config: { maxSnippets: 400 },
};
await fs.writeFile(metaPath, JSON.stringify(fresh, null, 2), "utf8");
return fresh;
}
}
export async function writeMeta(
chatId: number,
meta: SmartContextMeta,
): Promise<void> {
const dir = getThreadDir(chatId);
await ensureDir(dir);
const metaPath = getMetaPath(chatId);
const updated: SmartContextMeta = {
...meta,
entityId: String(chatId),
updatedAt: Date.now(),
};
await fs.writeFile(metaPath, JSON.stringify(updated, null, 2), "utf8");
}
export async function updateRollingSummary(
chatId: number,
summary: string,
): Promise<SmartContextMeta> {
const meta = await readMeta(chatId);
const summaryTokens = estimateTokens(summary || "");
const next: SmartContextMeta = {
...meta,
rollingSummary: summary,
summaryTokens,
};
await writeMeta(chatId, next);
return next;
}
export async function appendSnippets(
chatId: number,
snippets: Omit<SmartContextSnippet, "id" | "ts" | "tokens">[],
): Promise<number> {
const dir = getThreadDir(chatId);
await ensureDir(dir);
const snippetsPath = getSnippetsPath(chatId);
const withDefaults: SmartContextSnippet[] = snippets.map((s) => ({
id: randomUUID(),
ts: Date.now(),
tokens: estimateTokens(s.text),
...s,
}));
const lines = withDefaults.map((obj) => JSON.stringify(obj)).join("\n");
await fs.appendFile(snippetsPath, (lines ? lines + "\n" : ""), "utf8");
// prune if exceeded max
const meta = await readMeta(chatId);
const maxSnippets = meta.config?.maxSnippets ?? 400;
try {
const file = await fs.readFile(snippetsPath, "utf8");
const allLines = file.split("\n").filter(Boolean);
if (allLines.length > maxSnippets) {
const toKeep = allLines.slice(allLines.length - maxSnippets);
await fs.writeFile(snippetsPath, toKeep.join("\n") + "\n", "utf8");
return toKeep.length;
}
return allLines.length;
} catch {
return withDefaults.length;
}
}
export async function readAllSnippets(chatId: number): Promise<SmartContextSnippet[]> {
try {
const raw = await fs.readFile(getSnippetsPath(chatId), "utf8");
return raw
.split("\n")
.filter(Boolean)
.map((line) => JSON.parse(line) as SmartContextSnippet);
} catch {
return [];
}
}
function normalize(value: number, min: number, max: number): number {
if (max === min) return 0;
return (value - min) / (max - min);
}
function keywordScore(text: string, query: string): number {
const toTokens = (s: string) =>
s
.toLowerCase()
.replace(/[^a-z0-9_\- ]+/g, " ")
.split(/\s+/)
.filter(Boolean);
const qTokens = new Set(toTokens(query));
const tTokens = toTokens(text);
if (qTokens.size === 0 || tTokens.length === 0) return 0;
let hits = 0;
for (const tok of tTokens) if (qTokens.has(tok)) hits++;
return hits / tTokens.length; // simple overlap ratio
}
export interface RetrieveContextResult {
rollingSummary?: string;
usedTokens: number;
snippets: SmartContextSnippet[];
}
export async function retrieveContext(
chatId: number,
query: string,
budgetTokens: number,
): Promise<RetrieveContextResult> {
const meta = await readMeta(chatId);
const snippets = await readAllSnippets(chatId);
const now = Date.now();
let minTs = now;
let maxTs = 0;
for (const s of snippets) {
if (s.ts < minTs) minTs = s.ts;
if (s.ts > maxTs) maxTs = s.ts;
}
const scored = snippets.map((s) => {
const recency = normalize(s.ts, minTs, maxTs);
const kw = keywordScore(s.text, query);
const base = 0.6 * kw + 0.4 * recency;
const score = base;
return { ...s, score } as SmartContextSnippet;
});
scored.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
const picked: SmartContextSnippet[] = [];
let usedTokens = 0;
for (const s of scored) {
const t = s.tokens ?? estimateTokens(s.text);
if (usedTokens + t > budgetTokens) break;
picked.push(s);
usedTokens += t;
}
const rollingSummary = meta.rollingSummary || "";
return { rollingSummary, usedTokens, snippets: picked };
}
export async function rebuildIndex(_chatId: number): Promise<void> {
// Placeholder for future embedding/vector index rebuild.
return;
}

View File

@@ -0,0 +1,13 @@
diff --git a/update-dyad.sh b/update-dyad.sh
index 2763b94..4d7da4c 100755
--- a/update-dyad.sh
+++ b/update-dyad.sh
@@ -78,7 +78,7 @@ git log --oneline HEAD..upstream/main --reverse
# Attempt to merge
print_status "Merging upstream changes into your branch..."
-if git merge upstream/main -m "merge: update from upstream - $(date)"; then
+if git merge upstream/main -m "merge: update from upstream - $(date)" --allow-unrelated-histories; then
print_success "✅ Update completed successfully!"
# Check for any conflicts that need manual resolution

View File

@@ -1,75 +0,0 @@
import { testSkipIfWindows } from "./helpers/test_helper";
import { expect } from "@playwright/test";
import fs from "fs";
testSkipIfWindows(
"annotator - capture and submit screenshot",
async ({ po }) => {
await po.setUpDyadPro({ autoApprove: true });
// Create a basic app
await po.sendPrompt("basic");
// Click the annotator button to activate annotator mode
await po.clickPreviewAnnotatorButton();
// Wait for annotator mode to be active
await po.waitForAnnotatorMode();
// Submit the screenshot to chat
await po.clickAnnotatorSubmit();
await expect(po.getChatInput()).toContainText(
"Please update the UI based on these screenshots",
);
// Verify the screenshot was attached to chat context
await po.sendPrompt("[dump]");
// Wait for the LLM response containing the dump path to appear in the UI
// before attempting to extract it from the messages list
await po.page.waitForSelector("text=/\\[\\[dyad-dump-path=.*\\]\\]/");
// Get the dump file path from the messages list
const messagesListText = await po.page
.getByTestId("messages-list")
.textContent();
const dumpPathMatch = messagesListText?.match(
/\[\[dyad-dump-path=([^\]]+)\]\]/,
);
if (!dumpPathMatch) {
throw new Error("No dump path found in messages list");
}
const dumpFilePath = dumpPathMatch[1];
const dumpContent = fs.readFileSync(dumpFilePath, "utf-8");
const parsedDump = JSON.parse(dumpContent);
// Get the last message from the dump
const messages = parsedDump.body.messages;
const lastMessage = messages[messages.length - 1];
expect(lastMessage).toBeTruthy();
expect(lastMessage.content).toBeTruthy();
// The content is an array with text and image parts
expect(Array.isArray(lastMessage.content)).toBe(true);
// Find the text part and verify it mentions the PNG attachment
const textPart = lastMessage.content.find(
(part: any) => part.type === "text",
);
expect(textPart).toBeTruthy();
expect(textPart.text).toMatch(/annotated-screenshot-.*\.png/);
expect(textPart.text).toMatch(/image\/png/);
// Find the image part and verify it has the correct structure
const imagePart = lastMessage.content.find(
(part: any) => part.type === "image_url",
);
expect(imagePart).toBeTruthy();
expect(imagePart.image_url).toBeTruthy();
expect(imagePart.image_url.url).toMatch(/^data:image\/png;base64,/);
},
);

View File

@@ -1,5 +1,4 @@
import { testSkipIfWindows, test } from "./helpers/test_helper";
import { expect } from "@playwright/test";
testSkipIfWindows("fix error with AI", async ({ po }) => {
await po.setUp({ autoApprove: true });
@@ -21,26 +20,6 @@ testSkipIfWindows("fix error with AI", async ({ po }) => {
await po.snapshotPreview();
});
testSkipIfWindows("copy error message from banner", async ({ po }) => {
await po.setUp({ autoApprove: true });
await po.sendPrompt("tc=create-error");
await po.page.getByText("Error Line 6 error", { exact: true }).waitFor({
state: "visible",
});
await po.clickCopyErrorMessage();
const clipboardText = await po.getClipboardText();
expect(clipboardText).toContain("Error Line 6 error");
expect(clipboardText.length).toBeGreaterThan(0);
await expect(po.page.getByRole("button", { name: "Copied" })).toBeVisible();
await expect(po.page.getByRole("button", { name: "Copied" })).toBeHidden({
timeout: 3000,
});
});
test("fix all errors button", async ({ po }) => {
await po.setUp({ autoApprove: true });
await po.sendPrompt("tc=create-multiple-errors");

View File

@@ -2,4 +2,3 @@ Here is a simple response to test the context limit banner functionality.
This message simulates being close to the model's context window limit.

View File

@@ -3,6 +3,7 @@ I will intentionally add an error
<dyad-write path="src/pages/Index.tsx" description="intentionally add an error">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
throw new Error("Line 6 error");
@@ -15,6 +16,7 @@ return (
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -3,6 +3,7 @@ I will intentionally add multiple errors to test the Fix All Errors button
<dyad-write path="src/pages/Index.tsx" description="intentionally add first error">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
throw new Error("First error in Index");
@@ -15,6 +16,7 @@ return (
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -1 +0,0 @@
1

View File

@@ -1 +0,0 @@
This is a simple basic response

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -341,11 +341,7 @@ export class PageObject {
async selectChatMode(mode: "build" | "ask" | "agent") {
await this.page.getByTestId("chat-mode-selector").click();
await this.page
.getByRole("option", {
name: mode === "agent" ? "Build with MCP (experimental)" : mode,
})
.click();
await this.page.getByRole("option", { name: mode }).click();
}
async openContextFilesPicker() {
@@ -557,22 +553,6 @@ export class PageObject {
await this.page.getByTestId("preview-open-browser-button").click();
}
async clickPreviewAnnotatorButton() {
await this.page
.getByTestId("preview-annotator-button")
.click({ timeout: Timeout.EXTRA_LONG });
}
async waitForAnnotatorMode() {
// Wait for the annotator toolbar to be visible
await expect(this.page.getByRole("button", { name: "Select" })).toBeVisible(
{ timeout: Timeout.MEDIUM },
);
}
async clickAnnotatorSubmit() {
await this.page.getByRole("button", { name: "Add to Chat" }).click();
}
locateLoadingAppPreview() {
return this.page.getByText("Preparing app preview...");
}
@@ -595,13 +575,6 @@ export class PageObject {
await this.page.getByRole("button", { name: "Fix error with AI" }).click();
}
async clickCopyErrorMessage() {
await this.page.getByRole("button", { name: /Copy/ }).click();
}
async getClipboardText(): Promise<string> {
return await this.page.evaluate(() => navigator.clipboard.readText());
}
async clickFixAllErrors() {
await this.page.getByRole("button", { name: /Fix All Errors/ }).click();
}

View File

@@ -1,150 +0,0 @@
import { expect } from "@playwright/test";
import { Timeout, testWithConfig } from "./helpers/test_helper";
import * as fs from "node:fs";
import * as path from "node:path";
testWithConfig({
preLaunchHook: async ({ userDataDir }) => {
// Set up a force-close scenario by creating settings with isRunning: true
// and lastKnownPerformance data
const settingsPath = path.join(userDataDir, "user-settings.json");
const settings = {
hasRunBefore: true,
isRunning: true, // Simulate force-close
enableAutoUpdate: false,
releaseChannel: "stable",
lastKnownPerformance: {
timestamp: Date.now() - 5000, // 5 seconds ago
memoryUsageMB: 256,
cpuUsagePercent: 45.5,
systemMemoryUsageMB: 8192,
systemMemoryTotalMB: 16384,
systemMemoryPercent: 50.0,
systemCpuPercent: 35.2,
},
};
fs.mkdirSync(userDataDir, { recursive: true });
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
},
})(
"force-close detection shows dialog with performance data",
async ({ po }) => {
// Wait for the home page to be visible first
await expect(po.getHomeChatInputContainer()).toBeVisible({
timeout: Timeout.LONG,
});
// Check if the force-close dialog is visible by looking for the heading
await expect(
po.page.getByRole("heading", { name: "Force Close Detected" }),
).toBeVisible({ timeout: Timeout.MEDIUM });
// Verify the warning message
await expect(
po.page.getByText(
"The app was not closed properly the last time it was running",
),
).toBeVisible();
// Verify performance data is displayed
await expect(po.page.getByText("Last Known State:")).toBeVisible();
// Check Process Metrics section
await expect(po.page.getByText("Process Metrics")).toBeVisible();
await expect(po.page.getByText("256 MB")).toBeVisible();
await expect(po.page.getByText("45.5%")).toBeVisible();
// Check System Metrics section
await expect(po.page.getByText("System Metrics")).toBeVisible();
await expect(po.page.getByText("8192 / 16384 MB")).toBeVisible();
await expect(po.page.getByText("35.2%")).toBeVisible();
// Close the dialog
await po.page.getByRole("button", { name: "OK" }).click();
// Verify dialog is closed by checking the heading is no longer visible
await expect(
po.page.getByRole("heading", { name: "Force Close Detected" }),
).not.toBeVisible();
},
);
testWithConfig({
preLaunchHook: async ({ userDataDir }) => {
// Set up scenario without force-close (proper shutdown)
const settingsPath = path.join(userDataDir, "user-settings.json");
const settings = {
hasRunBefore: true,
isRunning: false, // Proper shutdown - no force-close
enableAutoUpdate: false,
releaseChannel: "stable",
lastKnownPerformance: {
timestamp: Date.now() - 5000,
memoryUsageMB: 256,
cpuUsagePercent: 45.5,
systemMemoryUsageMB: 8192,
systemMemoryTotalMB: 16384,
systemMemoryPercent: 50.0,
systemCpuPercent: 35.2,
},
};
fs.mkdirSync(userDataDir, { recursive: true });
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
},
})("no force-close dialog when app was properly shut down", async ({ po }) => {
// Verify the home page loaded normally
await expect(po.getHomeChatInputContainer()).toBeVisible({
timeout: Timeout.LONG,
});
// Verify that the force-close dialog is NOT shown
await expect(
po.page.getByRole("heading", { name: "Force Close Detected" }),
).not.toBeVisible();
});
testWithConfig({})(
"performance information is being captured during normal operation",
async ({ po, electronApp }) => {
// Wait for the app to load
await expect(po.getHomeChatInputContainer()).toBeVisible({
timeout: Timeout.LONG,
});
// Get the user data directory
const userDataDir = (electronApp as any).$dyadUserDataDir;
const settingsPath = path.join(userDataDir, "user-settings.json");
// Wait a bit to allow performance monitoring to capture at least one data point
// Performance monitoring runs every 30 seconds, but we'll wait 35 seconds to be safe
await po.page.waitForTimeout(35000);
// Read the settings file
const settingsContent = fs.readFileSync(settingsPath, "utf-8");
const settings = JSON.parse(settingsContent);
// Verify that lastKnownPerformance exists and has all required fields
expect(settings.lastKnownPerformance).toBeDefined();
expect(settings.lastKnownPerformance.timestamp).toBeGreaterThan(0);
expect(settings.lastKnownPerformance.memoryUsageMB).toBeGreaterThan(0);
expect(
settings.lastKnownPerformance.cpuUsagePercent,
).toBeGreaterThanOrEqual(0);
expect(settings.lastKnownPerformance.systemMemoryUsageMB).toBeGreaterThan(
0,
);
expect(settings.lastKnownPerformance.systemMemoryTotalMB).toBeGreaterThan(
0,
);
expect(
settings.lastKnownPerformance.systemCpuPercent,
).toBeGreaterThanOrEqual(0);
// Verify the timestamp is recent (within the last minute)
const now = Date.now();
const timeDiff = now - settings.lastKnownPerformance.timestamp;
expect(timeDiff).toBeLessThan(60000); // Less than 1 minute old
},
);

View File

@@ -1,15 +0,0 @@
import { testSkipIfWindows } from "./helpers/test_helper";
testSkipIfWindows("smart context balanced - simple", async ({ po }) => {
await po.setUpDyadPro({ autoApprove: true });
const proModesDialog = await po.openProModesDialog({
location: "home-chat-input-container",
});
await proModesDialog.setSmartContextMode("balanced");
await proModesDialog.close();
await po.sendPrompt("[dump]");
await po.snapshotServerDump("request");
await po.snapshotMessages({ replaceDumpPath: true });
});

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": false,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -2276,6 +2276,7 @@ export default App;
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
"@tanstack/react-query": "^5.56.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
@@ -7548,6 +7549,7 @@ createRoot(document.getElementById("root")!).render(<App />);
}
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
const addToRemoveQueue = (toastId: string) => {
if (toastTimeouts.has(toastId)) {
return;
@@ -7558,6 +7560,7 @@ const Index = () => {
dispatch({
type: "REMOVE_TOAST",
toastId: toastId,
});
}, TOAST_REMOVE_DELAY);
toastTimeouts.set(toastId, timeout);

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -18,6 +18,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -319,6 +319,7 @@ export default App;
=== src/components/made-with-dyad.tsx ===
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -5591,6 +5592,7 @@ createRoot(document.getElementById("root")!).render(<App />);
=== src/pages/Index.tsx ===
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -5601,6 +5603,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -316,6 +316,7 @@ export default App;
=== src/components/made-with-dyad.tsx ===
export const MadeWithDyad = ; href="https://www.dyad.sh/"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
@@ -5584,6 +5585,7 @@ createRoot(document.getElementById("root")!).render(<App />);
=== src/pages/Index.tsx ===
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -5594,6 +5596,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -88,6 +88,7 @@
},
{
"path": "src/components/made-with-dyad.tsx",
"content": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"force": false
},
{
@@ -362,6 +363,7 @@
},
{
"path": "src/pages/Index.tsx",
"content": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"force": false
},
{

View File

@@ -28,6 +28,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -82,6 +83,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -28,6 +28,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -82,6 +83,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -33,6 +33,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -87,6 +88,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -33,6 +33,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -87,6 +88,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -33,6 +33,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -87,6 +88,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -7,12 +7,11 @@
- img
- text: "src/pages/Index.tsx Summary: intentionally add first error"
- img
- text: Error First error in Index...
- img
- button "Copy":
- img
- text: Error
- button "Fix with AI":
- img
- text: First error in Index...
- img
- img
- text: ErrorComponent.tsx
- button "Edit":
@@ -20,12 +19,11 @@
- img
- text: "src/components/ErrorComponent.tsx Summary: intentionally add second error"
- img
- text: Error Second error in ErrorComponent...
- img
- button "Copy":
- img
- text: Error
- button "Fix with AI":
- img
- text: Second error in ErrorComponent...
- img
- img
- text: helper.ts
- button "Edit":
@@ -33,12 +31,11 @@
- img
- text: "src/utils/helper.ts Summary: intentionally add third error"
- img
- text: Error Third error in helper...
- img
- button "Copy":
- img
- text: Error
- button "Fix with AI":
- img
- text: Third error in helper...
- img
- button "Fix All Errors (3)":
- img
- button:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -88,6 +88,7 @@
},
{
"path": "src/components/made-with-dyad.tsx",
"content": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"force": false
},
{
@@ -362,6 +363,7 @@
},
{
"path": "src/pages/Index.tsx",
"content": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"force": false
},
{

View File

@@ -247,6 +247,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -803,6 +804,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -813,6 +815,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "beta",
"isRunning": true,
"isTestMode": true
}

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -253,6 +253,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -809,6 +810,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -819,6 +821,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -244,6 +244,7 @@ export default App;
</dyad-file>
<dyad-file path="src/components/made-with-dyad.tsx">
export const MadeWithDyad = () => {
return (
<div className="p-4 text-center">
<a
@@ -800,6 +801,7 @@ createRoot(document.getElementById("root")!).render(<App />);
<dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -810,6 +812,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -5,5 +5,6 @@
- button "Deselect component":
- img
- img
- text: a src/components/made-with-dyad.tsx:4
- button "Deselect component":
- img

View File

@@ -5,3 +5,4 @@
- paragraph: Start building your amazing project here!
- link "Made with Dyad":
- /url: https://www.dyad.sh/
- text: a src/components/made-with-dyad.tsx

View File

@@ -1,5 +1,6 @@
- text: Selected Components (1)
- button "Clear all"
- img
- text: a src/components/made-with-dyad.tsx:4
- button "Deselect component":
- img

View File

@@ -66,6 +66,7 @@ role: user
message: This is my codebase. <dyad-file path="src/pages/Index.tsx">
// Update this page (the content is just a fallback if you fail to update the page)
import { MadeWithDyad } from "@/components/made-with-dyad";
const Index = () => {
return (
@@ -76,6 +77,7 @@ const Index = () => {
Start building your amazing project here!
</p>
</div>
<MadeWithDyad />
</div>
);
};

View File

@@ -118,6 +118,7 @@ You need to first add Supabase to your app and then we can add auth.
===
role: user
message: This is my codebase. <dyad-file path="src/app/page.tsx">
import { MadeWithDyad } from "@/components/made-with-dyad";
export default function Home() {
return (
@@ -125,6 +126,7 @@ export default function Home() {
<main className="flex flex-col gap-8 row-start-1 items-center sm:items-start">
<h1>Blank page</h1>
</main>
<MadeWithDyad />
</div>
);
}
@@ -158,5 +160,6 @@ Snippet:
<main className="flex flex-col gap-8 row-start-1 items-center sm:items-start">
<h1>Blank page</h1> // <-- EDIT HERE
</main>
<MadeWithDyad />
</div>
```

View File

@@ -5,3 +5,4 @@
- paragraph: Start building your amazing project here!
- link "Made with Dyad":
- /url: https://www.dyad.sh/
- text: a src/components/made-with-dyad.tsx

View File

@@ -5,5 +5,6 @@
- button "Deselect component":
- img
- img
- text: a src/components/made-with-dyad.tsx:4
- button "Deselect component":
- img

View File

@@ -1,12 +0,0 @@
- paragraph: "[dump]"
- paragraph: "[[dyad-dump-path=*]]"
- button:
- img
- img
- text: Approved
- img
- text: less than a minute ago
- button "Request ID":
- img
- button "Retry":
- img

File diff suppressed because one or more lines are too long

View File

@@ -88,6 +88,7 @@
},
{
"path": "src/components/made-with-dyad.tsx",
"content": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"force": false
},
{
@@ -362,6 +363,7 @@
},
{
"path": "src/pages/Index.tsx",
"content": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"force": false
},
{

View File

@@ -57,6 +57,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -121,6 +122,7 @@
"a96b9ba5e40d95b92adf56431fdf9cbe25b5c2557621f0666615bff6889dfc50": "{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"lib\": [\"ES2023\"],\n \"module\": \"ESNext\",\n \"skipLibCheck\": true,\n\n /* Bundler mode */\n \"moduleResolution\": \"bundler\",\n \"allowImportingTsExtensions\": true,\n \"isolatedModules\": true,\n \"moduleDetection\": \"force\",\n \"noEmit\": true,\n\n /* Linting */\n \"strict\": true,\n \"noUnusedLocals\": false,\n \"noUnusedParameters\": false,\n \"noFallthroughCasesInSwitch\": true\n },\n \"include\": [\"vite.config.ts\"]\n}\n",
"29afc6166ec968586a13e65e526754525abfbac1ef73ad5c6b9c75e2c16697f7": "{\n \"$schema\": \"https://openapi.vercel.sh/vercel.json\",\n \"rewrites\": [\n {\n \"source\": \"/(.*)\",\n \"destination\": \"/index.html\"\n }\n ]\n}\n",
"92e6e1a0685f5d2cbe4e9f58d9fd2e8cb74d7ec6b0c93bfd25341edf47f3c130": "import { defineConfig } from \"vite\";\nimport dyadComponentTagger from \"@dyad-sh/react-vite-component-tagger\";\nimport react from \"@vitejs/plugin-react-swc\";\nimport path from \"path\";\n\nexport default defineConfig(() => ({\n server: {\n host: \"::\",\n port: 8080,\n },\n plugins: [dyadComponentTagger(), react()],\n resolve: {\n alias: {\n \"@\": path.resolve(__dirname, \"./src\"),\n },\n },\n}));\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n"
},
"fileReferences": [
{

View File

@@ -24,6 +24,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -24,6 +24,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -15,6 +15,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -15,6 +15,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -15,6 +15,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -16,6 +16,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -17,6 +17,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -17,6 +17,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -14,7 +14,7 @@
},
{
"role": "assistant",
"content": "1"
"content": "Error: Test case file not found: 1.md"
},
{
"role": "user",
@@ -41,6 +41,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -95,6 +96,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -14,7 +14,7 @@
},
{
"role": "assistant",
"content": "1"
"content": "Error: Test case file not found: 1.md"
},
{
"role": "user",
@@ -49,6 +49,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -103,6 +104,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -14,7 +14,7 @@
},
{
"role": "assistant",
"content": "1"
"content": "Error: Test case file not found: 1.md"
},
{
"role": "user",
@@ -57,6 +57,7 @@
"5f1387ce504f44bce8e80b0f29e6aee60c3e8227c70db37231ad0dadb0117fe0": "# Welcome to your Dyad app\n",
"a0715e0a09edbd0fbde65816a75e0fa0fc8b314c5260c0768c19bf3aac22621a": "#root {\n max-width: 1280px;\n margin: 0 auto;\n padding: 2rem;\n text-align: center;\n}\n\n.logo {\n height: 6em;\n padding: 1.5em;\n will-change: filter;\n transition: filter 300ms;\n}\n.logo:hover {\n filter: drop-shadow(0 0 2em #646cffaa);\n}\n.logo.react:hover {\n filter: drop-shadow(0 0 2em #61dafbaa);\n}\n\n@keyframes logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n a:nth-of-type(2) .logo {\n animation: logo-spin infinite 20s linear;\n }\n}\n\n.card {\n padding: 2em;\n}\n\n.read-the-docs {\n color: #888;\n}\n",
"4e69ef9f71a824d0a6b0965300a4738f34e54a39d58433104162a61b6d072d49": "import { Toaster } from \"@/components/ui/toaster\";\nimport { Toaster as Sonner } from \"@/components/ui/sonner\";\nimport { TooltipProvider } from \"@/components/ui/tooltip\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { BrowserRouter, Routes, Route } from \"react-router-dom\";\nimport Index from \"./pages/Index\";\nimport NotFound from \"./pages/NotFound\";\n\nconst queryClient = new QueryClient();\n\nconst App = () => (\n <QueryClientProvider client={queryClient}>\n <TooltipProvider>\n <Toaster />\n <Sonner />\n <BrowserRouter>\n <Routes>\n <Route path=\"/\" element={<Index />} />\n {/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL \"*\" ROUTE */}\n <Route path=\"*\" element={<NotFound />} />\n </Routes>\n </BrowserRouter>\n </TooltipProvider>\n </QueryClientProvider>\n);\n\nexport default App;\n",
"b8d3ed0643f99b45851f98668e6ca4163004a878967abd283373393753c26666": "export const MadeWithDyad = () => {\n return (\n <div className=\"p-4 text-center\">\n <a\n href=\"https://www.dyad.sh/\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200\"\n >\n Made with Dyad\n </a>\n </div>\n );\n};\n",
"b728b30af5d9f770a34d5b4ae85ea720c90664fa55d83ad3d9835f48f20f5846": "import * as React from \"react\";\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst Accordion = AccordionPrimitive.Root;\n\nconst AccordionItem = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>\n>(({ className, ...props }, ref) => (\n <AccordionPrimitive.Item\n ref={ref}\n className={cn(\"border-b\", className)}\n {...props}\n />\n));\nAccordionItem.displayName = \"AccordionItem\";\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Header className=\"flex\">\n <AccordionPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronDown className=\"h-4 w-4 shrink-0 transition-transform duration-200\" />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n));\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef<typeof AccordionPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>\n>(({ className, children, ...props }, ref) => (\n <AccordionPrimitive.Content\n ref={ref}\n className=\"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down\"\n {...props}\n >\n <div className={cn(\"pb-4 pt-0\", className)}>{children}</div>\n </AccordionPrimitive.Content>\n));\n\nAccordionContent.displayName = AccordionPrimitive.Content.displayName;\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent };\n",
"6f5d2b743e097cc0f38a8201fc9472bbcffa7ef80653eb09ac1733f470dd675c": "import * as React from \"react\";\nimport * as AlertDialogPrimitive from \"@radix-ui/react-alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { buttonVariants } from \"@/components/ui/button\";\n\nconst AlertDialog = AlertDialogPrimitive.Root;\n\nconst AlertDialogTrigger = AlertDialogPrimitive.Trigger;\n\nconst AlertDialogPortal = AlertDialogPrimitive.Portal;\n\nconst AlertDialogOverlay = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Overlay>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Overlay\n className={cn(\n \"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0\",\n className,\n )}\n {...props}\n ref={ref}\n />\n));\nAlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;\n\nconst AlertDialogContent = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <AlertDialogPortal>\n <AlertDialogOverlay />\n <AlertDialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg\",\n className,\n )}\n {...props}\n />\n </AlertDialogPortal>\n));\nAlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;\n\nconst AlertDialogHeader = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col space-y-2 text-center sm:text-left\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogHeader.displayName = \"AlertDialogHeader\";\n\nconst AlertDialogFooter = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\n \"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\",\n className,\n )}\n {...props}\n />\n);\nAlertDialogFooter.displayName = \"AlertDialogFooter\";\n\nconst AlertDialogTitle = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Title>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Title\n ref={ref}\n className={cn(\"text-lg font-semibold\", className)}\n {...props}\n />\n));\nAlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;\n\nconst AlertDialogDescription = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Description>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nAlertDialogDescription.displayName =\n AlertDialogPrimitive.Description.displayName;\n\nconst AlertDialogAction = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Action>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Action\n ref={ref}\n className={cn(buttonVariants(), className)}\n {...props}\n />\n));\nAlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;\n\nconst AlertDialogCancel = React.forwardRef<\n React.ElementRef<typeof AlertDialogPrimitive.Cancel>,\n React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>\n>(({ className, ...props }, ref) => (\n <AlertDialogPrimitive.Cancel\n ref={ref}\n className={cn(\n buttonVariants({ variant: \"outline\" }),\n \"mt-2 sm:mt-0\",\n className,\n )}\n {...props}\n />\n));\nAlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;\n\nexport {\n AlertDialog,\n AlertDialogPortal,\n AlertDialogOverlay,\n AlertDialogTrigger,\n AlertDialogContent,\n AlertDialogHeader,\n AlertDialogFooter,\n AlertDialogTitle,\n AlertDialogDescription,\n AlertDialogAction,\n AlertDialogCancel,\n};\n",
"050c08a3ec850a8fae8579b2bdbb4c9b8aa64744b580f07e2b26f7e6fc17dac0": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n));\nAlert.displayName = \"Alert\";\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n));\nAlertTitle.displayName = \"AlertTitle\";\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n));\nAlertDescription.displayName = \"AlertDescription\";\n\nexport { Alert, AlertTitle, AlertDescription };\n",
@@ -111,6 +112,7 @@
"4b70ac2ad6f1c640249bb43667f86d8447985c49be8bd0335897ad0ae7c70694": "import * as React from \"react\";\n\nimport type { ToastActionElement, ToastProps } from \"@/components/ui/toast\";\n\nconst TOAST_LIMIT = 1;\nconst TOAST_REMOVE_DELAY = 1000000;\n\ntype ToasterToast = ToastProps & {\n id: string;\n title?: React.ReactNode;\n description?: React.ReactNode;\n action?: ToastActionElement;\n};\n\nconst _actionTypes = {\n ADD_TOAST: \"ADD_TOAST\",\n UPDATE_TOAST: \"UPDATE_TOAST\",\n DISMISS_TOAST: \"DISMISS_TOAST\",\n REMOVE_TOAST: \"REMOVE_TOAST\",\n} as const;\n\nlet count = 0;\n\nfunction genId() {\n count = (count + 1) % Number.MAX_SAFE_INTEGER;\n return count.toString();\n}\n\ntype ActionType = typeof _actionTypes;\n\ntype Action =\n | {\n type: ActionType[\"ADD_TOAST\"];\n toast: ToasterToast;\n }\n | {\n type: ActionType[\"UPDATE_TOAST\"];\n toast: Partial<ToasterToast>;\n }\n | {\n type: ActionType[\"DISMISS_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n }\n | {\n type: ActionType[\"REMOVE_TOAST\"];\n toastId?: ToasterToast[\"id\"];\n };\n\ninterface State {\n toasts: ToasterToast[];\n}\n\nconst toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n\nconst addToRemoveQueue = (toastId: string) => {\n if (toastTimeouts.has(toastId)) {\n return;\n }\n\n const timeout = setTimeout(() => {\n toastTimeouts.delete(toastId);\n dispatch({\n type: \"REMOVE_TOAST\",\n toastId: toastId,\n });\n }, TOAST_REMOVE_DELAY);\n\n toastTimeouts.set(toastId, timeout);\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"ADD_TOAST\":\n return {\n ...state,\n toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),\n };\n\n case \"UPDATE_TOAST\":\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === action.toast.id ? { ...t, ...action.toast } : t,\n ),\n };\n\n case \"DISMISS_TOAST\": {\n const { toastId } = action;\n\n // ! Side effects ! - This could be extracted into a dismissToast() action,\n // but I'll keep it here for simplicity\n if (toastId) {\n addToRemoveQueue(toastId);\n } else {\n state.toasts.forEach((toast) => {\n addToRemoveQueue(toast.id);\n });\n }\n\n return {\n ...state,\n toasts: state.toasts.map((t) =>\n t.id === toastId || toastId === undefined\n ? {\n ...t,\n open: false,\n }\n : t,\n ),\n };\n }\n case \"REMOVE_TOAST\":\n if (action.toastId === undefined) {\n return {\n ...state,\n toasts: [],\n };\n }\n return {\n ...state,\n toasts: state.toasts.filter((t) => t.id !== action.toastId),\n };\n }\n};\n\nconst listeners: Array<(state: State) => void> = [];\n\nlet memoryState: State = { toasts: [] };\n\nfunction dispatch(action: Action) {\n memoryState = reducer(memoryState, action);\n listeners.forEach((listener) => {\n listener(memoryState);\n });\n}\n\ntype Toast = Omit<ToasterToast, \"id\">;\n\nfunction toast({ ...props }: Toast) {\n const id = genId();\n\n const update = (props: ToasterToast) =>\n dispatch({\n type: \"UPDATE_TOAST\",\n toast: { ...props, id },\n });\n const dismiss = () => dispatch({ type: \"DISMISS_TOAST\", toastId: id });\n\n dispatch({\n type: \"ADD_TOAST\",\n toast: {\n ...props,\n id,\n open: true,\n onOpenChange: (open) => {\n if (!open) dismiss();\n },\n },\n });\n\n return {\n id: id,\n dismiss,\n update,\n };\n}\n\nfunction useToast() {\n const [state, setState] = React.useState<State>(memoryState);\n\n React.useEffect(() => {\n listeners.push(setState);\n return () => {\n const index = listeners.indexOf(setState);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n };\n }, [state]);\n\n return {\n ...state,\n toast,\n dismiss: (toastId?: string) => dispatch({ type: \"DISMISS_TOAST\", toastId }),\n };\n}\n\nexport { useToast, toast };\n",
"d1f1e0d62cb8d8d1e04c26e14de842d8a151f75812d81b046c65b5d1fe8e4b27": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n",
"5cbfd5e41e9218faa071fd97a799497ba5e31423f3a38d4d16adae98a11b80a4": "import { createRoot } from \"react-dom/client\";\nimport App from \"./App.tsx\";\nimport \"./globals.css\";\n\ncreateRoot(document.getElementById(\"root\")!).render(<App />);\n",
"70618b5f415d91c92bef86039e35d5f282e959276bf49ed204c9f78f7490c99c": "// Update this page (the content is just a fallback if you fail to update the page)\n\nimport { MadeWithDyad } from \"@/components/made-with-dyad\";\n\nconst Index = () => {\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your Blank App</h1>\n <p className=\"text-xl text-gray-600\">\n Start building your amazing project here!\n </p>\n </div>\n <MadeWithDyad />\n </div>\n );\n};\n\nexport default Index;\n",
"940578bf01ac3dbdcb16f52528bd59903b2cce7698c8b39064f2791022567b0e": "import { useLocation } from \"react-router-dom\";\nimport { useEffect } from \"react\";\n\nconst NotFound = () => {\n const location = useLocation();\n\n useEffect(() => {\n console.error(\n \"404 Error: User attempted to access non-existent route:\",\n location.pathname,\n );\n }, [location.pathname]);\n\n return (\n <div className=\"min-h-screen flex items-center justify-center bg-gray-100\">\n <div className=\"text-center\">\n <h1 className=\"text-4xl font-bold mb-4\">404</h1>\n <p className=\"text-xl text-gray-600 mb-4\">Oops! Page not found</p>\n <a href=\"/\" className=\"text-blue-500 hover:text-blue-700 underline\">\n Return to Home\n </a>\n </div>\n </div>\n );\n};\n\nexport default NotFound;\n",
"328f94e9c711410b23188484a0a2f38886d7732d5c375cefcba442ab6195783f": "import { toast } from \"sonner\";\n\nexport const showSuccess = (message: string) => {\n toast.success(message);\n};\n\nexport const showError = (message: string) => {\n toast.error(message);\n};\n\nexport const showLoading = (message: string) => {\n return toast.loading(message);\n};\n\nexport const dismissToast = (toastId: string) => {\n toast.dismiss(toastId);\n};\n",
"65996936fbb042915f7b74a200fcdde7e410f32a669b1ab9597cfaa4b0faddb5": "/// <reference types=\"vite/client\" />\n",

View File

@@ -24,6 +24,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

View File

@@ -25,6 +25,5 @@
"enableAutoFixProblems": false,
"enableAutoUpdate": true,
"releaseChannel": "stable",
"isRunning": true,
"isTestMode": true
}

Some files were not shown because too many files have changed in this diff Show More