@encorekit/web-sdk 0.1.0 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -9
- package/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/umd/encore.min.js +1 -1
- package/dist/umd/encore.min.js.map +1 -1
- package/examples/README.md +149 -0
- package/examples/angular/README.md +210 -0
- package/examples/angular/angular.json +73 -0
- package/examples/angular/package.json +32 -0
- package/examples/angular/src/app/app.component.html +56 -0
- package/examples/angular/src/app/app.component.ts +114 -0
- package/examples/angular/src/app/encore.service.ts +83 -0
- package/examples/angular/src/index.html +13 -0
- package/examples/angular/src/main.ts +7 -0
- package/examples/angular/src/styles.css +225 -0
- package/examples/angular/tsconfig.json +33 -0
- package/examples/react/README.md +186 -0
- package/examples/react/index.html +13 -0
- package/examples/react/package.json +24 -0
- package/examples/react/src/App.tsx +173 -0
- package/examples/react/src/index.css +227 -0
- package/examples/react/src/main.tsx +11 -0
- package/examples/react/src/vite-env.d.ts +2 -0
- package/examples/react/tsconfig.json +25 -0
- package/examples/react/vite.config.ts +8 -0
- package/examples/svelte/README.md +233 -0
- package/examples/svelte/index.html +13 -0
- package/examples/svelte/package.json +25 -0
- package/examples/svelte/src/App.svelte +164 -0
- package/examples/svelte/src/app.css +224 -0
- package/examples/svelte/src/main.ts +9 -0
- package/examples/svelte/src/vite-env.d.ts +3 -0
- package/examples/svelte/svelte.config.js +8 -0
- package/examples/svelte/tsconfig.json +16 -0
- package/examples/svelte/tsconfig.node.json +11 -0
- package/examples/svelte/vite.config.ts +8 -0
- package/examples/vanilla-js/README.md +271 -0
- package/examples/vanilla-js/index.html +421 -0
- package/examples/vue/README.md +212 -0
- package/examples/vue/index.html +13 -0
- package/examples/vue/package.json +22 -0
- package/examples/vue/src/App.vue +170 -0
- package/examples/vue/src/main.ts +6 -0
- package/examples/vue/src/style.css +224 -0
- package/examples/vue/src/vite-env.d.ts +2 -0
- package/examples/vue/tsconfig.json +25 -0
- package/examples/vue/vite.config.ts +8 -0
- package/package.json +15 -2
- package/types/api/APIClient.d.ts.map +1 -1
- package/types/api/models.d.ts +6 -4
- package/types/api/models.d.ts.map +1 -1
- package/types/core/Encore.d.ts +12 -12
- package/types/core/Encore.d.ts.map +1 -1
- package/types/core/EntitlementManager.d.ts +9 -0
- package/types/core/EntitlementManager.d.ts.map +1 -1
- package/types/types.d.ts.map +1 -1
- package/types/ui/OfferCard.d.ts.map +1 -1
- package/types/ui/OfferCarousel.d.ts.map +1 -1
- package/types/ui/Tooltip.d.ts +22 -0
- package/types/ui/Tooltip.d.ts.map +1 -0
- package/types/ui/styles.d.ts.map +1 -1
- package/dist/cjs/index.js +0 -2
- package/dist/cjs/index.js.map +0 -1
- package/types/src/api/APIClient.d.ts +0 -63
- package/types/src/api/APIClient.d.ts.map +0 -1
- package/types/src/api/endpoints.d.ts +0 -35
- package/types/src/api/endpoints.d.ts.map +0 -1
- package/types/src/api/models.d.ts +0 -156
- package/types/src/api/models.d.ts.map +0 -1
- package/types/src/core/Configuration.d.ts +0 -42
- package/types/src/core/Configuration.d.ts.map +0 -1
- package/types/src/core/Encore.d.ts +0 -81
- package/types/src/core/Encore.d.ts.map +0 -1
- package/types/src/core/EntitlementManager.d.ts +0 -65
- package/types/src/core/EntitlementManager.d.ts.map +0 -1
- package/types/src/core/OfferManager.d.ts +0 -35
- package/types/src/core/OfferManager.d.ts.map +0 -1
- package/types/src/core/PlacementBuilder.d.ts +0 -27
- package/types/src/core/PlacementBuilder.d.ts.map +0 -1
- package/types/src/core/SignalManager.d.ts +0 -51
- package/types/src/core/SignalManager.d.ts.map +0 -1
- package/types/src/core/StorageManager.d.ts +0 -34
- package/types/src/core/StorageManager.d.ts.map +0 -1
- package/types/src/core/VerificationPoller.d.ts +0 -27
- package/types/src/core/VerificationPoller.d.ts.map +0 -1
- package/types/src/index.d.ts +0 -7
- package/types/src/index.d.ts.map +0 -1
- package/types/src/types.d.ts +0 -156
- package/types/src/types.d.ts.map +0 -1
- package/types/src/ui/OfferCard.d.ts +0 -29
- package/types/src/ui/OfferCard.d.ts.map +0 -1
- package/types/src/ui/OfferCarousel.d.ts +0 -55
- package/types/src/ui/OfferCarousel.d.ts.map +0 -1
- package/types/src/ui/OfferModal.d.ts +0 -41
- package/types/src/ui/OfferModal.d.ts.map +0 -1
- package/types/src/ui/SuccessScreen.d.ts +0 -33
- package/types/src/ui/SuccessScreen.d.ts.map +0 -1
- package/types/src/ui/styles.d.ts +0 -44
- package/types/src/ui/styles.d.ts.map +0 -1
- package/types/src/utils/eventEmitter.d.ts +0 -50
- package/types/src/utils/eventEmitter.d.ts.map +0 -1
- package/types/src/utils/focusDetection.d.ts +0 -21
- package/types/src/utils/focusDetection.d.ts.map +0 -1
- package/types/src/utils/logger.d.ts +0 -21
- package/types/src/utils/logger.d.ts.map +0 -1
- package/types/src/utils/network.d.ts +0 -57
- package/types/src/utils/network.d.ts.map +0 -1
- package/types/src/utils/uuid.d.ts +0 -10
- package/types/src/utils/uuid.d.ts.map +0 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Encore SDK - React Example
|
|
2
|
+
|
|
3
|
+
This example demonstrates how to integrate the Encore Web SDK into a React application using Vite and TypeScript.
|
|
4
|
+
|
|
5
|
+
## 🚀 Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies
|
|
9
|
+
npm install
|
|
10
|
+
|
|
11
|
+
# Start development server
|
|
12
|
+
npm run dev
|
|
13
|
+
|
|
14
|
+
# Build for production
|
|
15
|
+
npm run build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The app will be available at `http://localhost:5173`
|
|
19
|
+
|
|
20
|
+
## 📁 Project Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
react/
|
|
24
|
+
├── src/
|
|
25
|
+
│ ├── App.tsx # Main application component
|
|
26
|
+
│ ├── main.tsx # Application entry point
|
|
27
|
+
│ ├── index.css # Global styles
|
|
28
|
+
│ └── vite-env.d.ts # Vite type definitions
|
|
29
|
+
├── index.html # HTML template
|
|
30
|
+
├── package.json # Dependencies and scripts
|
|
31
|
+
├── tsconfig.json # TypeScript configuration
|
|
32
|
+
└── vite.config.ts # Vite configuration
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 🔑 Configuration
|
|
36
|
+
|
|
37
|
+
Before running the example, replace `'YOUR_API_KEY_HERE'` in `src/App.tsx` with your actual Encore API key:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
Encore.configure({
|
|
41
|
+
apiKey: 'YOUR_API_KEY_HERE', // Get this from dashboard.encorekit.com
|
|
42
|
+
environment: 'production',
|
|
43
|
+
logLevel: 'debug',
|
|
44
|
+
})
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 🎯 Features Demonstrated
|
|
48
|
+
|
|
49
|
+
### 1. SDK Initialization
|
|
50
|
+
The SDK is initialized when the component mounts using `useEffect`:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
Encore.configure({
|
|
55
|
+
apiKey: 'YOUR_API_KEY_HERE',
|
|
56
|
+
environment: 'production',
|
|
57
|
+
logLevel: 'debug',
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const currentUserId = Encore.getCurrentUserId()
|
|
61
|
+
setUserId(currentUserId || '')
|
|
62
|
+
setIsInitialized(true)
|
|
63
|
+
}, [])
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2. User Identification
|
|
67
|
+
Users can be identified with custom IDs and attributes:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const handleIdentifyUser = () => {
|
|
71
|
+
Encore.identify(customUserId, {
|
|
72
|
+
email: 'user@example.com',
|
|
73
|
+
})
|
|
74
|
+
setUserId(customUserId)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 3. Presenting Offers
|
|
79
|
+
Display targeted offers to users:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const handlePresentOffer = async () => {
|
|
83
|
+
const result = await Encore.presentOffer()
|
|
84
|
+
|
|
85
|
+
if (result.granted) {
|
|
86
|
+
console.log('Offer granted!')
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 🏗️ React Patterns
|
|
92
|
+
|
|
93
|
+
This example uses React best practices:
|
|
94
|
+
|
|
95
|
+
- **Hooks** - `useState` and `useEffect` for state and lifecycle management
|
|
96
|
+
- **TypeScript** - Full type safety with TypeScript
|
|
97
|
+
- **Error Handling** - Try-catch blocks for SDK operations
|
|
98
|
+
- **User Feedback** - Status messages for all actions
|
|
99
|
+
- **Disabled States** - Buttons disabled until SDK is initialized
|
|
100
|
+
|
|
101
|
+
## 📦 Dependencies
|
|
102
|
+
|
|
103
|
+
- `react` ^18.3.1 - React library
|
|
104
|
+
- `react-dom` ^18.3.1 - React DOM renderer
|
|
105
|
+
- `@encorekit/web-sdk` ^0.2.0 - Encore Web SDK
|
|
106
|
+
- `vite` ^5.4.1 - Build tool and dev server
|
|
107
|
+
- `typescript` ^5.5.3 - TypeScript compiler
|
|
108
|
+
|
|
109
|
+
## 🔧 Available Scripts
|
|
110
|
+
|
|
111
|
+
- `npm run dev` - Start development server with hot reload
|
|
112
|
+
- `npm run build` - Build for production
|
|
113
|
+
- `npm run preview` - Preview production build locally
|
|
114
|
+
|
|
115
|
+
## 💡 Best Practices
|
|
116
|
+
|
|
117
|
+
1. **Initialize Once** - Initialize the SDK in a top-level component or custom hook
|
|
118
|
+
2. **Error Handling** - Always wrap SDK calls in try-catch blocks
|
|
119
|
+
3. **User Feedback** - Provide clear feedback for all SDK operations
|
|
120
|
+
4. **Environment Variables** - In production, use environment variables for the API key
|
|
121
|
+
5. **Type Safety** - Use TypeScript for better developer experience
|
|
122
|
+
|
|
123
|
+
## 🎨 Customization
|
|
124
|
+
|
|
125
|
+
### Using Environment Variables
|
|
126
|
+
|
|
127
|
+
Create a `.env` file:
|
|
128
|
+
|
|
129
|
+
```env
|
|
130
|
+
VITE_ENCORE_API_KEY=your-api-key-here
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Update `App.tsx`:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
Encore.configure({
|
|
137
|
+
apiKey: import.meta.env.VITE_ENCORE_API_KEY,
|
|
138
|
+
environment: 'production',
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Creating a Custom Hook
|
|
143
|
+
|
|
144
|
+
For better reusability, create a custom hook:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// hooks/useEncore.ts
|
|
148
|
+
import { useState, useEffect } from 'react'
|
|
149
|
+
import Encore from '@encorekit/web-sdk'
|
|
150
|
+
|
|
151
|
+
export function useEncore(apiKey: string) {
|
|
152
|
+
const [isInitialized, setIsInitialized] = useState(false)
|
|
153
|
+
const [userId, setUserId] = useState<string>('')
|
|
154
|
+
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
Encore.configure({ apiKey })
|
|
157
|
+
setUserId(Encore.getCurrentUserId() || '')
|
|
158
|
+
setIsInitialized(true)
|
|
159
|
+
}, [apiKey])
|
|
160
|
+
|
|
161
|
+
const presentOffer = async () => {
|
|
162
|
+
return await Encore.presentOffer()
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const identify = (userId: string, attributes?: Record<string, any>) => {
|
|
166
|
+
Encore.identify(userId, attributes)
|
|
167
|
+
setUserId(userId)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return { isInitialized, userId, presentOffer, identify }
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 📚 Learn More
|
|
175
|
+
|
|
176
|
+
- [Encore SDK Documentation](https://docs.encorekit.com)
|
|
177
|
+
- [React Documentation](https://react.dev)
|
|
178
|
+
- [Vite Documentation](https://vitejs.dev)
|
|
179
|
+
- [TypeScript Documentation](https://www.typescriptlang.org)
|
|
180
|
+
|
|
181
|
+
## 🆘 Support
|
|
182
|
+
|
|
183
|
+
- 📧 Email: admin@encorekit.com
|
|
184
|
+
- 📖 Docs: https://docs.encorekit.com
|
|
185
|
+
|
|
186
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Encore SDK - React Example</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
13
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "encore-sdk-react-example",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "React example for Encore Web SDK",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@encorekit/web-sdk": "^0.1.1",
|
|
13
|
+
"react": "^18.3.1",
|
|
14
|
+
"react-dom": "^18.3.1"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/react": "^18.3.3",
|
|
18
|
+
"@types/react-dom": "^18.3.0",
|
|
19
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
20
|
+
"typescript": "^5.5.3",
|
|
21
|
+
"vite": "^5.4.1"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import Encore from '@encorekit/web-sdk'
|
|
3
|
+
|
|
4
|
+
function App() {
|
|
5
|
+
const [isInitialized, setIsInitialized] = useState(false)
|
|
6
|
+
const [userId, setUserId] = useState<string>('')
|
|
7
|
+
const [customUserId, setCustomUserId] = useState('')
|
|
8
|
+
const [status, setStatus] = useState<{
|
|
9
|
+
message: string
|
|
10
|
+
type: 'info' | 'success' | 'error'
|
|
11
|
+
} | null>(null)
|
|
12
|
+
|
|
13
|
+
// Initialize SDK on mount
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
try {
|
|
16
|
+
Encore.configure({
|
|
17
|
+
apiKey: 'ENCORE_PUBLIC_API_KEY', // Replace with your actual API key
|
|
18
|
+
userId: 'test-react',
|
|
19
|
+
environment: 'production',
|
|
20
|
+
logLevel: 'debug',
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
const currentUserId = Encore.getCurrentUserId()
|
|
24
|
+
setUserId(currentUserId || '')
|
|
25
|
+
setIsInitialized(true)
|
|
26
|
+
setStatus({
|
|
27
|
+
message: 'Encore SDK initialized successfully!',
|
|
28
|
+
type: 'success',
|
|
29
|
+
})
|
|
30
|
+
} catch (error) {
|
|
31
|
+
setStatus({
|
|
32
|
+
message: `Failed to initialize SDK: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
33
|
+
type: 'error',
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
}, [])
|
|
37
|
+
|
|
38
|
+
const handleIdentifyUser = () => {
|
|
39
|
+
if (!customUserId.trim()) {
|
|
40
|
+
setStatus({
|
|
41
|
+
message: 'Please enter a user ID',
|
|
42
|
+
type: 'error',
|
|
43
|
+
})
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
Encore.identify(customUserId, {
|
|
49
|
+
email: 'user@example.com',
|
|
50
|
+
})
|
|
51
|
+
setUserId(customUserId)
|
|
52
|
+
setStatus({
|
|
53
|
+
message: `User identified as: ${customUserId}`,
|
|
54
|
+
type: 'success',
|
|
55
|
+
})
|
|
56
|
+
} catch (error) {
|
|
57
|
+
setStatus({
|
|
58
|
+
message: `Failed to identify user: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
59
|
+
type: 'error',
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const handlePresentOffer = async () => {
|
|
65
|
+
setStatus({
|
|
66
|
+
message: 'Presenting offer...',
|
|
67
|
+
type: 'info',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const result = await Encore.presentOffer()
|
|
72
|
+
|
|
73
|
+
if (result.granted) {
|
|
74
|
+
setStatus({
|
|
75
|
+
message: 'Offer granted successfully!',
|
|
76
|
+
type: 'success',
|
|
77
|
+
})
|
|
78
|
+
} else {
|
|
79
|
+
setStatus({
|
|
80
|
+
message: `Offer not granted: ${JSON.stringify(result.reason)}`,
|
|
81
|
+
type: 'info',
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
} catch (error) {
|
|
85
|
+
setStatus({
|
|
86
|
+
message: `Failed to present offer: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
87
|
+
type: 'error',
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div className="app">
|
|
94
|
+
<h1>🎯 Encore SDK</h1>
|
|
95
|
+
<p>React Example</p>
|
|
96
|
+
|
|
97
|
+
<div className="card">
|
|
98
|
+
<h2>SDK Status</h2>
|
|
99
|
+
<div className="user-info">
|
|
100
|
+
<strong>Status:</strong> {isInitialized ? '✓ Initialized' : '✗ Not Initialized'}
|
|
101
|
+
<br />
|
|
102
|
+
<strong>User ID:</strong> {userId || 'Not set'}
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
{status && (
|
|
106
|
+
<div className={`status ${status.type}`}>
|
|
107
|
+
{status.message}
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div className="card">
|
|
113
|
+
<h2>User Identification</h2>
|
|
114
|
+
<div className="input-group">
|
|
115
|
+
<label htmlFor="userId">Custom User ID:</label>
|
|
116
|
+
<input
|
|
117
|
+
id="userId"
|
|
118
|
+
type="text"
|
|
119
|
+
placeholder="Enter user ID (e.g., user-123)"
|
|
120
|
+
value={customUserId}
|
|
121
|
+
onChange={(e) => setCustomUserId(e.target.value)}
|
|
122
|
+
disabled={!isInitialized}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
<button
|
|
126
|
+
onClick={handleIdentifyUser}
|
|
127
|
+
disabled={!isInitialized}
|
|
128
|
+
className="primary"
|
|
129
|
+
>
|
|
130
|
+
Identify User
|
|
131
|
+
</button>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<div className="card">
|
|
135
|
+
<h2>Present Offer</h2>
|
|
136
|
+
<p>Click the button below to display an offer to the user.</p>
|
|
137
|
+
<button
|
|
138
|
+
onClick={handlePresentOffer}
|
|
139
|
+
disabled={!isInitialized}
|
|
140
|
+
className="success"
|
|
141
|
+
>
|
|
142
|
+
🎁 Present Offer
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div className="card">
|
|
147
|
+
<h2>Code Example</h2>
|
|
148
|
+
<pre>
|
|
149
|
+
{`// Initialize SDK
|
|
150
|
+
Encore.configure({
|
|
151
|
+
apiKey: 'your-api-key',
|
|
152
|
+
userId: 'user-123',
|
|
153
|
+
environment: 'production',
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// Identify user
|
|
157
|
+
Encore.identify('user-123', {
|
|
158
|
+
email: 'user@example.com'
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
// Present offer
|
|
162
|
+
const result = await Encore.presentOffer()
|
|
163
|
+
if (result.granted) {
|
|
164
|
+
console.log('Offer granted!')
|
|
165
|
+
}`}
|
|
166
|
+
</pre>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export default App
|
|
173
|
+
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
color: rgba(255, 255, 255, 0.87);
|
|
8
|
+
background-color: #242424;
|
|
9
|
+
|
|
10
|
+
font-synthesis: none;
|
|
11
|
+
text-rendering: optimizeLegibility;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
* {
|
|
17
|
+
margin: 0;
|
|
18
|
+
padding: 0;
|
|
19
|
+
box-sizing: border-box;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
body {
|
|
23
|
+
margin: 0;
|
|
24
|
+
display: flex;
|
|
25
|
+
place-items: center;
|
|
26
|
+
min-width: 320px;
|
|
27
|
+
min-height: 100vh;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
#root {
|
|
31
|
+
width: 100%;
|
|
32
|
+
max-width: 1280px;
|
|
33
|
+
margin: 0 auto;
|
|
34
|
+
padding: 2rem;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
h1 {
|
|
38
|
+
font-size: 3.2em;
|
|
39
|
+
line-height: 1.1;
|
|
40
|
+
margin-bottom: 1rem;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
h2 {
|
|
44
|
+
font-size: 1.8em;
|
|
45
|
+
margin-top: 2rem;
|
|
46
|
+
margin-bottom: 1rem;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.app {
|
|
50
|
+
text-align: center;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.card {
|
|
54
|
+
padding: 2em;
|
|
55
|
+
background-color: #1a1a1a;
|
|
56
|
+
border-radius: 8px;
|
|
57
|
+
margin-bottom: 2rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.user-info {
|
|
61
|
+
margin: 1.5rem 0;
|
|
62
|
+
padding: 1rem;
|
|
63
|
+
background-color: #2a2a2a;
|
|
64
|
+
border-radius: 4px;
|
|
65
|
+
font-family: monospace;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.user-info strong {
|
|
69
|
+
color: #646cff;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.button-group {
|
|
73
|
+
display: flex;
|
|
74
|
+
gap: 1rem;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
flex-wrap: wrap;
|
|
77
|
+
margin: 1.5rem 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
button {
|
|
81
|
+
border-radius: 8px;
|
|
82
|
+
border: 1px solid transparent;
|
|
83
|
+
padding: 0.6em 1.2em;
|
|
84
|
+
font-size: 1em;
|
|
85
|
+
font-weight: 500;
|
|
86
|
+
font-family: inherit;
|
|
87
|
+
background-color: #1a1a1a;
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
transition: border-color 0.25s;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
button:hover {
|
|
93
|
+
border-color: #646cff;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
button:focus,
|
|
97
|
+
button:focus-visible {
|
|
98
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
button:disabled {
|
|
102
|
+
opacity: 0.5;
|
|
103
|
+
cursor: not-allowed;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
button:disabled:hover {
|
|
107
|
+
border-color: transparent;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.primary {
|
|
111
|
+
background-color: #646cff;
|
|
112
|
+
color: white;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.primary:hover {
|
|
116
|
+
background-color: #535bf2;
|
|
117
|
+
border-color: #535bf2;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.success {
|
|
121
|
+
background-color: #059669;
|
|
122
|
+
color: white;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.success:hover {
|
|
126
|
+
background-color: #047857;
|
|
127
|
+
border-color: #047857;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.status {
|
|
131
|
+
margin: 1rem 0;
|
|
132
|
+
padding: 0.8rem;
|
|
133
|
+
border-radius: 4px;
|
|
134
|
+
font-size: 0.9em;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.status.info {
|
|
138
|
+
background-color: #1e40af;
|
|
139
|
+
color: white;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.status.success {
|
|
143
|
+
background-color: #059669;
|
|
144
|
+
color: white;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.status.error {
|
|
148
|
+
background-color: #dc2626;
|
|
149
|
+
color: white;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.input-group {
|
|
153
|
+
margin: 1rem 0;
|
|
154
|
+
text-align: left;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.input-group label {
|
|
158
|
+
display: block;
|
|
159
|
+
margin-bottom: 0.5rem;
|
|
160
|
+
font-weight: 500;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.input-group input {
|
|
164
|
+
width: 100%;
|
|
165
|
+
padding: 0.6em;
|
|
166
|
+
border-radius: 4px;
|
|
167
|
+
border: 1px solid #444;
|
|
168
|
+
background-color: #1a1a1a;
|
|
169
|
+
color: inherit;
|
|
170
|
+
font-size: 1em;
|
|
171
|
+
font-family: inherit;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.input-group input:focus {
|
|
175
|
+
outline: 2px solid #646cff;
|
|
176
|
+
border-color: #646cff;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
code {
|
|
180
|
+
background-color: #2a2a2a;
|
|
181
|
+
padding: 0.2em 0.4em;
|
|
182
|
+
border-radius: 3px;
|
|
183
|
+
font-family: monospace;
|
|
184
|
+
font-size: 0.9em;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
pre {
|
|
188
|
+
text-align: left;
|
|
189
|
+
background-color: #1a1a1a;
|
|
190
|
+
padding: 1rem;
|
|
191
|
+
border-radius: 4px;
|
|
192
|
+
overflow-x: auto;
|
|
193
|
+
margin: 1rem 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@media (prefers-color-scheme: light) {
|
|
197
|
+
:root {
|
|
198
|
+
color: #213547;
|
|
199
|
+
background-color: #ffffff;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
button {
|
|
203
|
+
background-color: #f9f9f9;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.card {
|
|
207
|
+
background-color: #f9f9f9;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.user-info {
|
|
211
|
+
background-color: #efefef;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.input-group input {
|
|
215
|
+
background-color: #ffffff;
|
|
216
|
+
border-color: #ccc;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
code {
|
|
220
|
+
background-color: #efefef;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
pre {
|
|
224
|
+
background-color: #f5f5f5;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
22
|
+
},
|
|
23
|
+
"include": ["src"]
|
|
24
|
+
}
|
|
25
|
+
|