Compare commits

...

92 Commits

Author SHA1 Message Date
Guido D'Orsi
fc55e5c8e8 Merge pull request #2384 from garden-co/changeset-release/main
Version Packages
2025-06-02 18:29:42 +02:00
github-actions[bot]
4a74ccf399 Version Packages 2025-06-02 16:23:15 +00:00
Guido D'Orsi
a442315995 Merge pull request #2266 from garden-co/feat/encrypt-decrypt-rnqc
feat: enable RNQC for encrypt/decrypt
2025-06-02 18:18:41 +02:00
Brad Anderson
0d5ee3ed07 feat: enable RNQC for encrypt/decrypt 2025-06-02 12:16:31 -04:00
Guido D'Orsi
4e32cae8a7 feat: make the packages versions fixed 2025-06-02 16:19:28 +02:00
Guido D'Orsi
49d721a29b fix: add prosemirror and tiptap to the linked changeset 2025-06-02 16:18:44 +02:00
Guido D'Orsi
2c6d27598d Merge pull request #2397 from garden-co/fix/recursive-profile-discriminated-union
fix: make checks on the discriminator field on z.discriminatedUnion more specific and less strict
2025-06-02 16:16:25 +02:00
Guido D'Orsi
e637cb0700 fix: restore implicit discriminators support 2025-06-02 14:37:55 +02:00
Trisha Lim
c42848ece9 Merge pull request #2275 from garden-co/improvement/supported-env
homepage: supported env section, take svelte out of experimental
2025-06-02 13:36:23 +01:00
Benjamin S. Leveritt
841a818dff Merge pull request #2330 from garden-co/2323-update-docs-with-coloaded
Replace `Account` and `Loaded` with `co.account` and `co.loaded` (respectively)
2025-06-02 12:07:26 +01:00
Benjamin S. Leveritt
f74881a3fe Remove me 2025-06-02 12:05:35 +01:00
Guido D'Orsi
c559054378 fix: add support for optional dates 2025-06-02 12:55:33 +02:00
Guido D'Orsi
d6d9c0adcb fix: make checks on the discriminator field on z.discriminatedUnion more specific and less strict 2025-06-02 12:31:05 +02:00
Guido D'Orsi
cdf9b5a71c Merge pull request #2391 from garden-co/fix/recursive-profile-discriminated-union
fix: support for recursive props on co.profile and for co.image inside z.discriminatedUnion
2025-06-02 12:00:37 +02:00
Guido D'Orsi
4b950bce14 fix: support for recursive props on co.profile and for co.image inside z.discriminatedUnion 2025-06-02 11:48:54 +02:00
Benjamin S. Leveritt
8343d8f0fe Formats co.texts with backticks 2025-06-02 10:45:40 +01:00
Benjamin S. Leveritt
eeb280f17b Replace Account with co.account 2025-06-02 10:45:39 +01:00
Benjamin S. Leveritt
a927334b40 Replaces Loaded with co.loaded 2025-06-02 10:45:39 +01:00
Benjamin S. Leveritt
be0c1bcda5 Merge pull request #2367 from joeinnes/patch-2
Remove unnecessary console.log
2025-06-02 10:30:58 +01:00
Trisha Lim
b861daca60 Merge pull request #2386 from garden-co/tobiaslins-patch-1
[website] Use `/next` import for analytics
2025-06-01 18:45:18 +01:00
Benjamin S. Leveritt
b4cd307eba Merge pull request #2383 from garden-co/update-team
update team page
2025-05-31 16:44:50 +01:00
Tobias Lins
1d0e83d3fa Update layout.tsx 2025-05-31 17:05:18 +02:00
Guido D'Orsi
be7c4c29a1 chore: changeset 2025-05-30 14:42:32 +02:00
Trisha Lim
ffa4db0b61 update team page 2025-05-29 21:09:15 +02:00
Trisha Lim
7daf992c51 Merge pull request #2382 from garden-co/fix/sync-link
fix link to self-host docs
2025-05-29 20:57:19 +02:00
Trisha Lim
333c583265 fix link to self-host docs 2025-05-29 20:43:32 +02:00
Guido D'Orsi
bfa5e14112 Merge pull request #1992 from boorad/feat/rn-sqlite-sync
refactor: RN sqlite adapters
2025-05-27 20:44:55 +02:00
Brad Anderson
dcdf89bba7 fix: re-enable android build in e2e run script 2025-05-26 11:50:36 -04:00
Brad Anderson
a6e6939015 chore: sync app namespace & e2e tests 2025-05-26 11:50:36 -04:00
Brad Anderson
71aa24054d chore: lock file after rebase 2025-05-26 11:50:36 -04:00
Guido D'Orsi
4c88421440 chore: await for WAL 2025-05-26 11:50:36 -04:00
Guido D'Orsi
64bad01d9a fix: fix expo-sqlite run 2025-05-26 11:50:36 -04:00
Brad Anderson
4dfa809a77 fix: update chat-rn landing page, invite clipboard values 2025-05-26 11:50:36 -04:00
Guido D'Orsi
726df167f8 chore: add get function 2025-05-26 11:50:36 -04:00
Guido D'Orsi
2f62cbde13 test: cover the sqlite async with tests 2025-05-26 11:50:36 -04:00
Guido D'Orsi
93ef74219d feat: add sqlite async managers 2025-05-26 11:50:36 -04:00
Guido D'Orsi
495aa81335 feat: configure the max blocking time on RN storage to 30ms 2025-05-26 11:50:36 -04:00
Guido D'Orsi
99caaba328 chore: remove unused import 2025-05-26 11:50:36 -04:00
Guido D'Orsi
4bfcc787a1 chore(sqlite): move the migration logic in SQLiteNodeBase 2025-05-26 11:50:36 -04:00
Guido D'Orsi
7e96eb12dd feat: unify sqlite storage clients 2025-05-26 11:50:35 -04:00
Brad Anderson
a71eba2eb5 chore: bump RN version for ios sim 18.4 bug 2025-05-26 11:50:35 -04:00
Brad Anderson
b129cf9328 fix: rebase main, sync only 2025-05-26 11:50:35 -04:00
Brad Anderson
a6e31c41b7 feat: expo sqlite uses WAL, all sqlite defaults to sync 2025-05-26 11:50:35 -04:00
Brad Anderson
47746ff9ba fix: sourceExts belongs in resolver 2025-05-26 11:50:35 -04:00
Brad Anderson
4e4319a546 fix: rawDBExecute (expo) needs return rows 2025-05-26 11:50:35 -04:00
Brad Anderson
d1de8baf1d fix: initialize must use raw db calls 2025-05-26 11:50:35 -04:00
Brad Anderson
d427a2a13c feat: add sync mode to sqlite client 2025-05-26 11:50:35 -04:00
Brad Anderson
1fa6c3987a refactor: RN sqlite adapters 2025-05-26 11:50:35 -04:00
Joe Innes
ddf49e532f Remove unnecessary console.log 2025-05-26 17:38:14 +02:00
Guido D'Orsi
a0c4ef72ef Merge pull request #2366 from garden-co/changeset-release/main
Version Packages
2025-05-26 14:46:53 +02:00
github-actions[bot]
99009a9054 Version Packages 2025-05-26 12:44:40 +00:00
Guido D'Orsi
e512df4eff fix: move to the latest stable version of Zod 2025-05-26 14:42:08 +02:00
pax-k
da3ede8b54 fix(cursor-docs): improved jazz general help rule 2025-05-26 13:29:01 +02:00
pax-k
56ed6d3271 fix(cursor-docs): improved jazz schema generation rule 2025-05-26 13:22:14 +02:00
pax-k
78112bb19a fix(cursor-docs): added jazz schema template 2025-05-26 13:04:39 +02:00
pax-k
ac6b0c6561 Merge branch 'main' of https://github.com/gardencmp/jazz 2025-05-26 12:51:20 +02:00
pax-k
632365a4fb fix(cursor-docs): added llms-full docs and updated the jazz schema generation rule 2025-05-26 12:51:12 +02:00
Guido D'Orsi
14f52dbc4e Merge pull request #2365 from garden-co/changeset-release/main
Version Packages
2025-05-26 12:48:04 +02:00
github-actions[bot]
82e4256e26 Version Packages 2025-05-26 10:07:42 +00:00
Guido D'Orsi
5e253cc717 chore: version bump 2025-05-26 11:12:59 +02:00
Guido D'Orsi
0c1663505c Merge pull request #2363 from garden-co/changeset-release/main
Version Packages
2025-05-26 11:07:20 +02:00
github-actions[bot]
ad85703373 Version Packages 2025-05-25 15:01:21 +00:00
Guido D'Orsi
3a6ec3791c Merge pull request #2364 from garden-co/fix/storage-group-deps
feat(react): API for SSR and Server Components
2025-05-25 16:58:34 +02:00
Guido D'Orsi
f9590f9120 feat(react): API for SSR and Server Components 2025-05-25 16:54:29 +02:00
Guido D'Orsi
706ebf87da Merge pull request #2357 from balazshevesi/main
Fix docs
2025-05-25 16:24:47 +02:00
Guido D'Orsi
00dd317a5d Merge pull request #2362 from garden-co/fix/storage-group-deps
fix(storage): align groups dependencies calculation to LocalNode
2025-05-25 16:24:04 +02:00
Guido D'Orsi
5ced45fb90 test: cover the group dependency loading with a test (temporary) 2025-05-25 15:35:00 +02:00
Guido D'Orsi
23daa7cdde fix(storage): align groups dependencies calculation to LocalNode 2025-05-25 14:34:50 +02:00
Guido D'Orsi
c018752c0c Merge pull request #2361 from garden-co/changeset-release/main
Version Packages
2025-05-24 22:54:04 +02:00
github-actions[bot]
ba3bdcc268 Version Packages 2025-05-24 20:31:26 +00:00
Guido D'Orsi
4177f6f92c Merge pull request #2360 from garden-co/feat/ssr
feat(react): add experimental_enableSSR
2025-05-24 22:28:20 +02:00
Guido D'Orsi
e32a1f7392 feat(react): add experimental_enableSSR 2025-05-24 19:11:23 +02:00
Guido D'Orsi
7c43fd37ae Merge pull request #2358 from garden-co/feat/improve-music-player-mobile
feat(music-player): make the ui usable on mobile
2025-05-24 18:37:59 +02:00
Guido D'Orsi
48168d619b feat(music-player): make the ui usable on mobile 2025-05-24 18:37:15 +02:00
Balazs Hevesi
1b9b9273e5 Update 0-14-0.mdx 2025-05-23 22:18:05 +02:00
Guido D'Orsi
2f4eada56c Merge pull request #2356 from garden-co/changeset-release/main
Version Packages
2025-05-23 21:37:52 +02:00
github-actions[bot]
709b3432d7 Version Packages 2025-05-23 19:33:52 +00:00
Guido D'Orsi
78a7672401 fix: update lockfile 2025-05-23 21:31:34 +02:00
Guido D'Orsi
bb214f0e8b fix: remove react-dom from the peerDependencies 2025-05-23 21:22:22 +02:00
Guido D'Orsi
8706398f74 Merge pull request #2355 from garden-co/changeset-release/main
Version Packages
2025-05-23 20:31:09 +02:00
github-actions[bot]
1502a6b421 Version Packages 2025-05-23 18:15:41 +00:00
Guido D'Orsi
f167112d99 fix: remove react and react-dom dev dependencies due to npm install issues 2025-05-23 20:12:58 +02:00
Guido D'Orsi
d4d6cb3307 Merge pull request #2354 from garden-co/changeset-release/main
Version Packages
2025-05-23 20:01:42 +02:00
github-actions[bot]
9565cdf323 Version Packages 2025-05-23 18:01:27 +00:00
Guido D'Orsi
dfb21ff0f2 fix: add missing deps for sqlite and secure storage 2025-05-23 19:59:08 +02:00
Guido D'Orsi
98d697fafb fix: remove react and react-native dev dependencies 2025-05-23 19:50:54 +02:00
Guido D'Orsi
9150d53f90 Merge pull request #2353 from garden-co/changeset-release/main
Version Packages
2025-05-23 19:46:39 +02:00
github-actions[bot]
ac7ecc278c Version Packages 2025-05-23 17:46:11 +00:00
Guido D'Orsi
99595bc7e3 fix: remove React Native specific steps only for chat-rn-expo 2025-05-23 19:42:45 +02:00
Guido D'Orsi
f5bae09679 fix: remove React Native specific steps as not required anymore 2025-05-23 19:40:51 +02:00
Trisha Lim
e7733a5428 take svelte out of experimental 2025-05-21 14:45:12 +01:00
Trisha Lim
4683cc7ada homepage: redesign supported env section 2025-05-19 16:29:43 +01:00
252 changed files with 20918 additions and 5269 deletions

View File

@@ -2,8 +2,8 @@
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [
"linked": [],
"fixed": [
[
"cojson",
"cojson-storage",
@@ -27,6 +27,8 @@
"jazz-react-native-core",
"jazz-react-native",
"jazz-react-native-media-images",
"jazz-richtext-prosemirror",
"jazz-richtext-tiptap",
"jazz-run",
"jazz-svelte",
"jazz-tools",

View File

@@ -38,7 +38,6 @@ jobs:
- name: chat-rn-expo App Pre Build
working-directory: ./examples/chat-rn-expo
run: |
pnpm build
pnpm expo prebuild --clean
- name: Install Maestro

3
.gitignore vendored
View File

@@ -20,6 +20,9 @@ __screenshots__
# Playwright
test-results
# Java
.java-version
.husky
.vscode/*

View File

@@ -1,5 +1,82 @@
# betterauth
## 0.1.21
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-betterauth-server-plugin@0.14.18
- jazz-inspector@0.14.18
- jazz-react@0.14.18
- jazz-react-auth-betterauth@0.14.18
- jazz-betterauth-client-plugin@0.14.18
## 0.1.20
### Patch Changes
- Updated dependencies [e512df4]
- jazz-betterauth-server-plugin@0.14.17
- jazz-tools@0.14.17
- jazz-betterauth-client-plugin@0.14.17
- jazz-inspector@0.14.17
- jazz-react@0.14.17
- jazz-react-auth-betterauth@0.14.17
## 0.1.19
### Patch Changes
- jazz-betterauth-server-plugin@0.14.16
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-react-auth-betterauth@0.14.16
- jazz-tools@0.14.16
- jazz-betterauth-client-plugin@0.14.16
## 0.1.18
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-betterauth-server-plugin@0.14.15
- jazz-inspector@0.14.15
- jazz-react-auth-betterauth@0.14.15
- jazz-tools@0.14.15
- jazz-betterauth-client-plugin@0.14.15
## 0.1.17
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-betterauth-server-plugin@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-betterauth@0.14.14
- jazz-betterauth-client-plugin@0.14.14
## 0.1.16
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
- jazz-react-auth-betterauth@0.14.13
## 0.1.15
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
- jazz-react-auth-betterauth@0.14.12
## 0.1.14
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "betterauth",
"version": "0.1.14",
"version": "0.1.21",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,69 @@
# chat-rn-expo-clerk
## 1.0.141
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-expo@0.14.18
- jazz-react-native-media-images@0.14.18
## 1.0.140
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-expo@0.14.17
- jazz-react-native-media-images@0.14.17
## 1.0.139
### Patch Changes
- jazz-expo@0.14.16
- jazz-tools@0.14.16
- jazz-react-native-media-images@0.14.16
## 1.0.138
### Patch Changes
- jazz-expo@0.14.15
- jazz-tools@0.14.15
- jazz-react-native-media-images@0.14.15
## 1.0.137
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-expo@0.14.14
- jazz-react-native-media-images@0.14.14
## 1.0.136
### Patch Changes
- jazz-expo@0.14.13
## 1.0.135
### Patch Changes
- jazz-expo@0.14.12
## 1.0.134
### Patch Changes
- Updated dependencies [98d697f]
- jazz-expo@0.14.11
## 1.0.133
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-expo-clerk",
"main": "index.js",
"version": "1.0.133",
"version": "1.0.141",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",

View File

@@ -1,5 +1,64 @@
# chat-rn-expo
## 1.0.9
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-expo@0.14.18
## 1.0.8
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-expo@0.14.17
## 1.0.7
### Patch Changes
- jazz-expo@0.14.16
- jazz-tools@0.14.16
## 1.0.6
### Patch Changes
- jazz-expo@0.14.15
- jazz-tools@0.14.15
## 1.0.5
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-expo@0.14.14
## 1.0.4
### Patch Changes
- jazz-expo@0.14.13
## 1.0.3
### Patch Changes
- jazz-expo@0.14.12
## 1.0.2
### Patch Changes
- Updated dependencies [98d697f]
- jazz-expo@0.14.11
## 1.0.1
### Patch Changes

View File

@@ -14,7 +14,7 @@
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.anonymous.chatrnexpo"
"bundleIdentifier": "tools.jazz.chatrnexpo"
},
"android": {
"adaptiveIcon": {
@@ -22,10 +22,11 @@
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true,
"package": "com.anonymous.chatrnexpo"
"package": "tools.jazz.chatrnexpo"
},
"web": {
"favicon": "./assets/favicon.png"
}
},
"plugins": ["expo-secure-store", "expo-sqlite"]
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn-expo",
"version": "1.0.1",
"version": "1.0.9",
"main": "index.ts",
"scripts": {
"build": "expo prebuild",
@@ -16,6 +16,8 @@
"@react-native-community/netinfo": "11.4.1",
"expo": "~53.0.9",
"expo-clipboard": "^7.1.4",
"expo-secure-store": "~14.2.3",
"expo-sqlite": "~15.2.10",
"expo-status-bar": "~2.2.3",
"jazz-expo": "workspace:*",
"jazz-tools": "workspace:*",

View File

@@ -2,7 +2,7 @@
# fully erased. The tap into the input field hits the middle, and clears all
# text to the left. If there's more to the right, it slides left, and thus we
# repeat this step. https://maestro.mobile.dev/api-reference/commands/erasetext
appId: com.jazz.chatrn
appId: tools.jazz.chatrnexpo
---
- copyTextFrom:
id: ${id}

View File

@@ -1,4 +1,4 @@
appId: com.jazz.chatrn
appId: tools.jazz.chatrnexpo
---
- launchApp

View File

@@ -3,14 +3,18 @@
# This script is necessary, because unlike ios, the android emulator action
# accepts a script, runs it as your tests, then terminates.
# set -e
set -e
# # build and install the app
# echo "Building and installing Android app."
# echo "If it fails, its output will be in artifact: android-install.log..."
# cd ./android/
# ./gradlew installRelease >> ~/output/android-install.log 2>&1
# cd ..
OUTPUT_FILE=~/output/android-install.log
mkdir -p ~/output
touch $OUTPUT_FILE
# build and install the app
echo "Building and installing Android app."
echo "If it fails, its output will be in artifact: android-install.log..."
cd ./android/
./gradlew installRelease >> $OUTPUT_FILE 2>&1
cd ..
# run the e2e tests
export PATH="$PATH":"$HOME/.maestro/bin"

View File

@@ -1,5 +1,73 @@
# chat-rn
## 1.0.136
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [0d5ee3e]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- cojson@0.14.18
- jazz-react-native@0.14.18
- cojson-transport-ws@0.14.18
## 1.0.135
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react-native@0.14.17
## 1.0.134
### Patch Changes
- Updated dependencies [5e253cc]
- cojson@0.14.16
- cojson-transport-ws@0.14.16
- jazz-react-native@0.14.16
- jazz-tools@0.14.16
## 1.0.133
### Patch Changes
- Updated dependencies [23daa7c]
- cojson@0.14.15
- jazz-react-native@0.14.15
- cojson-transport-ws@0.14.15
- jazz-tools@0.14.15
## 1.0.132
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react-native@0.14.14
## 1.0.131
### Patch Changes
- jazz-react-native@0.14.13
## 1.0.130
### Patch Changes
- jazz-react-native@0.14.12
## 1.0.129
### Patch Changes
- Updated dependencies [98d697f]
- jazz-react-native@0.14.11
## 1.0.128
### Patch Changes

View File

@@ -26,7 +26,7 @@ This will set up and launch the app on iOS. For Android, you can skip `pnpm pods
This was created using the following command:
```bash
pnpx @react-native-community/cli init chat-rn --version 0.76.7 --install-pods true --skip-git-init true --package-name com.chatrn --directory chat-rn
pnpx @react-native-community/cli init chat-rn --version 0.76.9 --install-pods true --skip-git-init true --package-name com.chatrn --directory chat-rn
```
Then change package name in `package.json`, and begin build instructions above.

View File

@@ -2,9 +2,9 @@
"name": "ChatRN",
"displayName": "ChatRN",
"android": {
"package": "com.anonymous.ChatRN"
"package": "tools.jazz.chatrn"
},
"ios": {
"bundleIdentifier": "com.anonymous.ChatRN"
"bundleIdentifier": "tools.jazz.chatrn"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ module.exports = makeMetroConfig({
resolveRequest: MetroSymlinksResolver(),
extraNodeModules,
nodeModulesPaths,
sourceExts: ["mjs", "js", "json", "ts", "tsx"],
},
sourceExts: ["mjs", "js", "json", "ts", "tsx"],
watchFolders,
});

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.128",
"version": "1.0.136",
"main": "index.js",
"scripts": {
"android": "react-native run-android",
@@ -40,10 +40,10 @@
"@react-native-community/cli": "15.0.1",
"@react-native-community/cli-platform-android": "15.0.1",
"@react-native-community/cli-platform-ios": "15.0.1",
"@react-native/babel-preset": "0.76.7",
"@react-native/eslint-config": "0.76.7",
"@react-native/metro-config": "0.76.7",
"@react-native/typescript-config": "0.76.7",
"@react-native/babel-preset": "0.76.9",
"@react-native/eslint-config": "0.76.9",
"@react-native/metro-config": "0.76.9",
"@react-native/typescript-config": "0.76.9",
"@rnx-kit/metro-config": "^2.0.1",
"@rnx-kit/metro-resolver-symlinks": "^0.2.1",
"@types/react": "^18.3.12",

View File

@@ -3,7 +3,6 @@ import { useAccount, useCoState } from "jazz-react-native";
import { CoPlainText, Group, ID, Loaded, Profile } from "jazz-tools";
import { useEffect, useState } from "react";
import {
Alert,
Button,
FlatList,
KeyboardAvoidingView,
@@ -19,6 +18,7 @@ import { Chat, Message } from "./schema";
export function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<string>();
const [chatIdInput, setChatIdInput] = useState<string>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
@@ -36,10 +36,8 @@ export function ChatScreen({ navigation }: { navigation: any }) {
<Button
onPress={() => {
if (loadedChat?.id) {
Clipboard.setString(
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
);
Alert.alert("Copied to clipboard", `Chat ID: ${loadedChat.id}`);
Clipboard.setString(loadedChat.id);
console.log("Copied to clipboard", `Chat ID: ${loadedChat.id}`);
}
}}
title="Share"
@@ -56,27 +54,11 @@ export function ChatScreen({ navigation }: { navigation: any }) {
};
const joinChat = () => {
Alert.prompt(
"Join Chat",
"Enter the Chat ID (example: co_zBGEHYvRfGuT2YSBraY3njGjnde)",
[
{
text: "Cancel",
style: "cancel",
},
{
text: "Join",
onPress: (chatId) => {
if (chatId) {
setChatId(chatId);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
},
},
],
"plain-text",
);
if (chatIdInput) {
setChatId(chatIdInput as ID<Chat>);
} else {
console.warn("Error: Chat ID cannot be empty.");
}
};
const sendMessage = () => {
@@ -153,6 +135,16 @@ export function ChatScreen({ navigation }: { navigation: any }) {
<TouchableOpacity onPress={createChat} style={styles.newChatButton}>
<Text style={styles.buttonText}>Start new chat</Text>
</TouchableOpacity>
<Text style={styles.usernameLabel}>Join existing chat</Text>
<TextInput
style={styles.chatIdInput}
placeholder="Chat ID"
value={chatIdInput ?? ""}
onChangeText={setChatIdInput}
textAlignVertical="center"
onSubmitEditing={joinChat}
testID="chat-id-input"
/>
<TouchableOpacity onPress={joinChat} style={styles.joinChatButton}>
<Text style={styles.buttonText}>Join chat</Text>
</TouchableOpacity>
@@ -205,27 +197,91 @@ export function ChatScreen({ navigation }: { navigation: any }) {
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
height: "100%",
},
welcomeContainer: {
flex: 1,
alignItems: "center",
justifyContent: "center",
padding: 16,
},
usernameLabel: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 16,
},
usernameInput: {
width: 160,
height: 48,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
paddingHorizontal: 8,
marginBottom: 24,
},
chatIdInput: {
width: 320,
height: 48,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
paddingHorizontal: 8,
marginBottom: 24,
marginTop: 8,
},
newChatButton: {
backgroundColor: "#3B82F6",
padding: 16,
borderRadius: 8,
marginBottom: 24,
},
joinChatButton: {
backgroundColor: "#10B981",
padding: 16,
borderRadius: 8,
},
buttonText: {
color: "white",
fontSize: 16,
fontWeight: "bold",
textAlign: "center",
},
messageList: {
flex: 1,
},
inputContainer: {
padding: 12,
},
inputWrapper: {
flexDirection: "row",
alignItems: "center",
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
paddingHorizontal: 12,
},
messageInput: {
flex: 1,
height: 32,
paddingHorizontal: 8,
},
sendButton: {
paddingHorizontal: 16,
},
messageContainer: {
borderRadius: 8,
paddingVertical: 4,
paddingHorizontal: 6,
maxWidth: "80%",
flexDirection: "column",
alignItems: "flex-start",
marginBottom: 8,
},
myMessage: {
backgroundColor: "#e5e7eb", // gray-200
alignSelf: "flex-end",
textAlign: "right",
},
otherMessage: {
backgroundColor: "#d1d5db", // gray-300
alignSelf: "flex-start",
},
senderName: {
fontSize: 12,
color: "#6b7280", // gray-500
color: "#666",
marginBottom: 4,
},
textRight: {
textAlign: "right",
@@ -234,92 +290,27 @@ const styles = StyleSheet.create({
textAlign: "left",
},
messageContent: {
position: "relative",
flexDirection: "row",
alignItems: "flex-end",
justifyContent: "space-between",
backgroundColor: "#f0f0f0",
borderRadius: 8,
padding: 8,
},
messageText: {
color: "#000000",
fontSize: 16,
maxWidth: "85%",
},
timestamp: {
fontSize: 10,
color: "#6b7280", // gray-500
textAlign: "right",
marginLeft: 8,
color: "#666",
marginTop: 4,
},
timestampOther: {
textAlign: "left",
marginTop: 8,
},
timestampMy: {
textAlign: "right",
marginTop: 4,
},
welcomeContainer: {
flex: 1,
flexDirection: "column",
height: "100%",
alignItems: "center",
justifyContent: "center",
},
usernameLabel: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 24,
},
usernameInput: {
borderRadius: 4,
height: 48,
padding: 8,
marginBottom: 48,
width: 160,
borderWidth: 1,
borderColor: "#e5e7eb", // gray-200
},
newChatButton: {
backgroundColor: "#3b82f6", // blue-500
padding: 16,
borderRadius: 6,
},
joinChatButton: {
backgroundColor: "#10b981", // green-500
padding: 16,
borderRadius: 6,
marginTop: 16,
},
buttonText: {
color: "white",
fontWeight: "600",
},
messageList: {
flex: 1,
},
inputContainer: {
paddingVertical: 16,
paddingHorizontal: 10,
backgroundColor: "white",
borderTopWidth: 1,
borderTopColor: "#d1d5db", // gray-300
},
inputWrapper: {
flex: 1,
flexDirection: "row",
alignItems: "center",
margin: 5,
},
messageInput: {
borderRadius: 20,
height: 32,
paddingVertical: 0,
paddingHorizontal: 8,
borderWidth: 1,
borderColor: "#e5e7eb", // gray-200
flex: 1,
},
sendButton: {
marginLeft: 10,
backgroundColor: "#d1d5db", // gray-300
avatar: {
borderRadius: 16,
height: 32,
width: 32,

View File

@@ -1,5 +1,50 @@
# chat-vue
## 0.0.116
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-browser@0.14.18
- jazz-vue@0.14.18
## 0.0.115
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-browser@0.14.17
- jazz-vue@0.14.17
## 0.0.114
### Patch Changes
- jazz-browser@0.14.16
- jazz-tools@0.14.16
- jazz-vue@0.14.16
## 0.0.113
### Patch Changes
- jazz-browser@0.14.15
- jazz-tools@0.14.15
- jazz-vue@0.14.15
## 0.0.112
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-browser@0.14.14
- jazz-vue@0.14.14
## 0.0.111
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.111",
"version": "0.0.116",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,65 @@
# jazz-example-chat
## 0.0.216
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-inspector@0.14.18
- jazz-react@0.14.18
## 0.0.215
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-inspector@0.14.17
- jazz-react@0.14.17
## 0.0.214
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.213
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.212
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.211
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.210
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.209
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.209",
"version": "0.0.216",
"type": "module",
"scripts": {
"dev": "vite",
@@ -21,7 +21,7 @@
"lucide-react": "^0.274.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"zod": "4.0.0-beta.20250505T012514"
"zod": "3.25.28"
},
"devDependencies": {
"@playwright/test": "^1.50.1",

View File

@@ -1,5 +1,65 @@
# minimal-auth-clerk
## 0.0.115
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
- jazz-react-auth-clerk@0.14.18
## 0.0.114
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
- jazz-react-auth-clerk@0.14.17
## 0.0.113
### Patch Changes
- jazz-react@0.14.16
- jazz-react-auth-clerk@0.14.16
- jazz-tools@0.14.16
## 0.0.112
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-react-auth-clerk@0.14.15
- jazz-tools@0.14.15
## 0.0.111
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-clerk@0.14.14
## 0.0.110
### Patch Changes
- jazz-react@0.14.13
- jazz-react-auth-clerk@0.14.13
## 0.0.109
### Patch Changes
- jazz-react@0.14.12
- jazz-react-auth-clerk@0.14.12
## 0.0.108
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.108",
"version": "0.0.115",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,62 @@
# file-share-svelte
## 0.0.100
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-inspector-element@0.14.18
- jazz-svelte@0.14.18
## 0.0.99
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-inspector-element@0.14.17
- jazz-svelte@0.14.17
## 0.0.98
### Patch Changes
- jazz-svelte@0.14.16
- jazz-tools@0.14.16
- jazz-inspector-element@0.14.16
## 0.0.97
### Patch Changes
- jazz-svelte@0.14.15
- jazz-tools@0.14.15
- jazz-inspector-element@0.14.15
## 0.0.96
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector-element@0.14.14
- jazz-svelte@0.14.14
## 0.0.95
### Patch Changes
- jazz-inspector-element@0.14.13
## 0.0.94
### Patch Changes
- jazz-inspector-element@0.14.12
## 0.0.93
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.93",
"version": "0.0.100",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,65 @@
# jazz-tailwind-demo-auth-starter
## 0.0.55
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-inspector@0.14.18
- jazz-react@0.14.18
## 0.0.54
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-inspector@0.14.17
- jazz-react@0.14.17
## 0.0.53
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.52
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.51
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.50
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.49
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.48
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "filestream",
"private": true,
"version": "0.0.48",
"version": "0.0.55",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,58 @@
# form
## 0.1.56
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.1.55
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.1.54
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.1.53
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.1.52
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.1.51
### Patch Changes
- jazz-react@0.14.13
## 0.1.50
### Patch Changes
- jazz-react@0.14.12
## 0.1.49
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.49",
"version": "0.1.56",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,58 @@
# image-upload
## 0.0.112
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.111
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.110
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.109
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.108
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.107
### Patch Changes
- jazz-react@0.14.13
## 0.0.106
### Patch Changes
- jazz-react@0.14.12
## 0.0.105
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.105",
"version": "0.0.112",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,56 @@
# jazz-example-inspector
## 0.0.165
### Patch Changes
- Updated dependencies [0d5ee3e]
- cojson@0.14.18
- jazz-inspector@0.14.18
- cojson-transport-ws@0.14.18
## 0.0.164
### Patch Changes
- jazz-inspector@0.14.17
## 0.0.163
### Patch Changes
- Updated dependencies [5e253cc]
- cojson@0.14.16
- cojson-transport-ws@0.14.16
- jazz-inspector@0.14.16
## 0.0.162
### Patch Changes
- Updated dependencies [23daa7c]
- cojson@0.14.15
- cojson-transport-ws@0.14.15
- jazz-inspector@0.14.15
## 0.0.161
### Patch Changes
- jazz-inspector@0.14.14
## 0.0.160
### Patch Changes
- jazz-inspector@0.14.13
## 0.0.159
### Patch Changes
- jazz-inspector@0.14.12
## 0.0.158
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.158",
"version": "0.0.165",
"type": "module",
"scripts": {
"dev": "vite",

41
examples/jazz-nextjs/.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -0,0 +1,42 @@
# jazz-nextjs
## 0.1.5
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.1.4
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.1.3
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.1.2
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.1.1
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14

View File

@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

View File

@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

View File

@@ -0,0 +1,26 @@
{
"name": "jazz-nextjs",
"version": "0.1.5",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.3.2",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4"
}
}

View File

@@ -0,0 +1,5 @@
const config = {
plugins: ["@tailwindcss/postcss"],
};
export default config;

View File

@@ -0,0 +1,26 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}

View File

@@ -0,0 +1,35 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { Jazz } from "../jazz";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<Jazz>{children}</Jazz>
</body>
</html>
);
}

View File

@@ -0,0 +1,46 @@
"use client";
import { useAccount } from "jazz-react";
import { Account } from "jazz-tools";
import Link from "next/link";
export default function Home() {
const { me } = useAccount(Account, {
resolve: {
profile: true,
},
});
return (
<div className="flex flex-col items-center justify-center h-screen gap-4">
<h1 className="text-2xl font-bold">SSR rendering example with Jazz</h1>
<div className="text-sm text-gray-500 w-1/2 text-center">
Data is still loaded only on the client, the components are rendered on
the server with all the CoValues as null
</div>
<label>
<div className="text-sm">
Your profile name{" "}
<span className="text-xs">(only loaded on the client)</span>
</div>
<input
className="border-2 border-gray-300 rounded-md p-2 w-full"
value={me?.profile.name ?? ""}
onChange={(e) => {
if (!me) {
return;
}
me.profile.name = e.target.value;
}}
/>
</label>
<Link
href={`/profile/${me?.profile.id}`}
className="bg-blue-500 text-white px-4 py-2 rounded-md"
>
Your profile name in a Server Component
</Link>
</div>
);
}

View File

@@ -0,0 +1,23 @@
import { jazzSSR } from "@/jazzSSR";
import { Profile } from "jazz-tools";
export default async function ServerSidePage(props: {
params: Promise<{ profileId: string }>;
}) {
const { profileId } = await props.params;
const profile = await Profile.load(profileId, {
loadAs: jazzSSR,
});
return (
<div className="flex flex-col items-center justify-center h-screen gap-4">
<h1 className="text-2xl font-bold">SSR rendering example with Jazz</h1>
<div className="text-sm text-gray-500 w-1/2 text-center">
This is a server component!
</div>
<label>
<div className="text-sm">Your profile name "{profile?.name}"</div>
</label>
</div>
);
}

View File

@@ -0,0 +1,16 @@
"use client";
import { JazzProvider } from "jazz-react";
export function Jazz({ children }: { children: React.ReactNode }) {
return (
<JazzProvider
experimental_enableSSR
sync={{
peer: `wss://cloud.jazz.tools/`,
}}
>
{children}
</JazzProvider>
);
}

View File

@@ -0,0 +1,5 @@
import { createSSRJazzAgent } from "jazz-react/ssr";
export const jazzSSR = createSSRJazzAgent({
peer: "wss://cloud.jazz.tools/",
});

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -1,5 +1,58 @@
# multi-cursors
## 0.0.108
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.107
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.106
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.105
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.104
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.103
### Patch Changes
- jazz-react@0.14.13
## 0.0.102
### Patch Changes
- jazz-react@0.14.12
## 0.0.101
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multi-cursors",
"private": true,
"version": "0.0.101",
"version": "0.0.108",
"type": "module",
"scripts": {
"dev": "vite",
@@ -17,7 +17,7 @@
"jazz-tools": "workspace:*",
"react": "19.0.0",
"react-dom": "19.0.0",
"zod": "3.25.0-beta.20250518T002810"
"zod": "3.25.28"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",

View File

@@ -1,5 +1,65 @@
# multiauth
## 0.0.56
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
- jazz-react-auth-clerk@0.14.18
## 0.0.55
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
- jazz-react-auth-clerk@0.14.17
## 0.0.54
### Patch Changes
- jazz-react@0.14.16
- jazz-react-auth-clerk@0.14.16
- jazz-tools@0.14.16
## 0.0.53
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-react-auth-clerk@0.14.15
- jazz-tools@0.14.15
## 0.0.52
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-clerk@0.14.14
## 0.0.51
### Patch Changes
- jazz-react@0.14.13
- jazz-react-auth-clerk@0.14.13
## 0.0.50
### Patch Changes
- jazz-react@0.14.12
- jazz-react-auth-clerk@0.14.12
## 0.0.49
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multiauth",
"private": true,
"version": "0.0.49",
"version": "0.0.56",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,65 @@
# jazz-example-musicplayer
## 0.0.137
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-inspector@0.14.18
- jazz-react@0.14.18
## 0.0.136
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-inspector@0.14.17
- jazz-react@0.14.17
## 0.0.135
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.134
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.133
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.132
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.131
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.130
### Patch Changes

View File

@@ -4,7 +4,7 @@
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"config": "tailwind.config.ts",
"css": "src/index.css",
"baseColor": "stone",
"cssVariables": true

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.130",
"version": "0.0.137",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,10 +16,11 @@
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-toast": "^1.1.4",
"@radix-ui/react-tooltip": "^1.1.6",
"class-variance-authority": "^0.7.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.0.0",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:*",

View File

@@ -7,11 +7,11 @@ import { RouterProvider, createHashRouter } from "react-router-dom";
import { HomePage } from "./3_HomePage";
import { useMediaPlayer } from "./5_useMediaPlayer";
import { InvitePage } from "./6_InvitePage";
import { PlayerControls } from "./components/PlayerControls";
import "./index.css";
import { MusicaAccount } from "@/1_schema";
import { apiKey } from "@/apiKey.ts";
import { SidebarProvider } from "@/components/ui/sidebar";
import { JazzProvider } from "jazz-react";
import { onAnonymousAccountDiscarded } from "./4_actions";
import { useUploadExampleData } from "./lib/useUploadExampleData";
@@ -50,7 +50,7 @@ function Main() {
return (
<>
<RouterProvider router={router} />
<PlayerControls mediaPlayer={mediaPlayer} />
{/* <PlayerControls mediaPlayer={mediaPlayer} /> */}
<Toaster />
</>
);
@@ -72,8 +72,10 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
defaultProfileName="Anonymous unicorn"
onAnonymousAccountDiscarded={onAnonymousAccountDiscarded}
>
<Main />
<JazzInspector />
<SidebarProvider>
<Main />
<JazzInspector />
</SidebarProvider>
</JazzProvider>
</React.StrictMode>,
);

View File

@@ -5,16 +5,16 @@ import {
useCoState,
useIsAuthenticated,
} from "jazz-react";
import { useNavigate, useParams } from "react-router";
import { useParams } from "react-router";
import { MusicaAccount, Playlist } from "./1_schema";
import { createNewPlaylist, uploadMusicTracks } from "./4_actions";
import { uploadMusicTracks } from "./4_actions";
import { MediaPlayer } from "./5_useMediaPlayer";
import { AuthButton } from "./components/AuthButton";
import { FileUploadButton } from "./components/FileUploadButton";
import { MusicTrackRow } from "./components/MusicTrackRow";
import { PlaylistTitleInput } from "./components/PlaylistTitleInput";
import { SidePanel } from "./components/SidePanel";
import { Button } from "./components/ui/button";
import { SidebarInset, SidebarTrigger } from "./components/ui/sidebar";
import { usePlayState } from "./lib/audio/usePlayState";
export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
@@ -26,7 +26,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
resolve: { root: { rootPlaylist: true, playlists: true } },
});
const navigate = useNavigate();
const playState = usePlayState();
const isPlaying = playState.value === "play";
const { toast } = useToast();
@@ -39,12 +38,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
await uploadMusicTracks(files);
}
async function handleCreatePlaylist() {
const playlist = await createNewPlaylist();
navigate(`/playlist/${playlist.id}`);
}
const params = useParams<{ playlistId: string }>();
const playlistId = params.playlistId ?? me?.root._refs.rootPlaylist.id;
@@ -71,10 +64,11 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
const isAuthenticated = useIsAuthenticated();
return (
<div className="flex flex-col h-screen text-gray-800 bg-blue-50">
<SidebarInset className="flex flex-col h-screen text-gray-800 bg-blue-50">
<div className="flex flex-1 overflow-hidden">
<SidePanel />
<SidePanel mediaPlayer={mediaPlayer} />
<main className="flex-1 p-6 overflow-y-auto">
<SidebarTrigger />
<div className="flex items-center justify-between mb-6">
{isRootPlaylist ? (
<h1 className="text-2xl font-bold text-blue-800">All tracks</h1>
@@ -87,7 +81,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
<FileUploadButton onFileLoad={handleFileLoad}>
Add file
</FileUploadButton>
<Button onClick={handleCreatePlaylist}>New playlist</Button>
</>
)}
{!isRootPlaylist && isAuthenticated && (
@@ -95,7 +88,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
Share playlist
</Button>
)}
<AuthButton />
</div>
</div>
<ul className="flex flex-col">
@@ -121,6 +113,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
</ul>
</main>
</div>
</div>
</SidebarInset>
);
}

View File

@@ -20,7 +20,7 @@ export function AuthButton() {
if (isAuthenticated) {
return (
<Button variant="outline" onClick={handleSignOut}>
<Button variant="ghost" onClick={handleSignOut}>
Sign out
</Button>
);
@@ -28,10 +28,7 @@ export function AuthButton() {
return (
<>
<Button
onClick={() => setOpen(true)}
className="bg-white text-black hover:bg-gray-100"
>
<Button onClick={() => setOpen(true)} variant="ghost">
Sign up
</Button>
<AuthModal open={open} onOpenChange={setOpen} />

View File

@@ -1,27 +1,40 @@
import { MusicaAccount } from "@/1_schema";
import { deletePlaylist } from "@/4_actions";
import { useAccount } from "jazz-react";
import { Trash2 } from "lucide-react";
import { MusicTrack, MusicaAccount } from "@/1_schema";
import { createNewPlaylist, deletePlaylist } from "@/4_actions";
import { MediaPlayer } from "@/5_useMediaPlayer";
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuAction,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar";
import { usePlayState } from "@/lib/audio/usePlayState";
import { useAccount, useCoState } from "jazz-react";
import { Home, Music, Pause, Play, Plus, Trash2 } from "lucide-react";
import { useNavigate, useParams } from "react-router";
import { LocalOnlyTag } from "./LocalOnlyTag";
import { AuthButton } from "./AuthButton";
export function SidePanel() {
export function SidePanel({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
const { playlistId } = useParams();
const navigate = useNavigate();
const { me } = useAccount(MusicaAccount, {
resolve: { root: { playlists: { $each: true } } },
});
function handleAllTracksClick(evt: React.MouseEvent<HTMLAnchorElement>) {
evt.preventDefault();
const playState = usePlayState();
const isPlaying = playState.value === "play";
function handleAllTracksClick() {
navigate(`/`);
}
function handlePlaylistClick(
evt: React.MouseEvent<HTMLAnchorElement>,
playlistId: string,
) {
evt.preventDefault();
function handlePlaylistClick(playlistId: string) {
navigate(`/playlist/${playlistId}`);
}
@@ -32,73 +45,121 @@ export function SidePanel() {
}
}
async function handleCreatePlaylist() {
const playlist = await createNewPlaylist();
navigate(`/playlist/${playlist.id}`);
}
const activeTrack = useCoState(MusicTrack, mediaPlayer.activeTrackId, {
resolve: { waveform: true },
});
const activeTrackTitle = activeTrack?.title;
return (
<aside className="w-64 p-6 bg-white overflow-y-auto">
<div className="flex items-center mb-1">
<svg
className="w-8 h-8 mr-2"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9 18V5l12-2v13"
stroke="#3b82f6"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6 15H3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM18 13h-3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2z"
fill="#3b82f6"
/>
</svg>
<span className="text-xl font-bold text-blue-600">Music Player</span>
</div>
<div className="mb-6">
<LocalOnlyTag />
</div>
<nav>
<h2 className="mb-2 text-sm font-semibold text-gray-600">Playlists</h2>
<ul className="space-y-1">
<li>
<a
href="#"
className={`block px-2 py-1 text-sm rounded ${
!playlistId ? "bg-blue-100 text-blue-600" : "hover:bg-blue-100"
}`}
onClick={handleAllTracksClick}
>
All tracks
</a>
</li>
{me?.root.playlists.map((playlist, index) => (
<li
key={index}
className={`px-2 py-1 flex transition-all duration-300 rounded items-center justify-between ${
playlist.id === playlistId ? "bg-blue-100" : ""
}`}
>
<a
href="#"
className={`w-full text-sm`}
onClick={(evt) => handlePlaylistClick(evt, playlist.id)}
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem className="flex items-center gap-2">
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-blue-600 text-white">
<svg
className="size-4"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{playlist.title}
</a>
{playlist.id === playlistId && (
<button
onClick={() => handleDeletePlaylist(playlist.id)}
className="ml-2 text-red-600 hover:text-red-800 animate-in fade-in scale-in duration-200"
aria-label={`Delete ${playlist.title}`}
>
<Trash2 size={16} />
</button>
)}
</li>
))}
</ul>
</nav>
</aside>
<path
d="M9 18V5l12-2v13"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6 15H3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM18 13h-3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2z"
fill="currentColor"
/>
</svg>
</div>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">Music Player</span>
</div>
<AuthButton />
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton onClick={handleAllTracksClick}>
<Home className="size-4" />
<span>Go to all tracks</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Playlists</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton onClick={handleCreatePlaylist}>
<Plus className="size-4" />
<span>Add a new playlist</span>
</SidebarMenuButton>
</SidebarMenuItem>
{me?.root.playlists.map((playlist) => (
<SidebarMenuItem key={playlist.id}>
<SidebarMenuButton
onClick={() => handlePlaylistClick(playlist.id)}
isActive={playlist.id === playlistId}
>
<div className="flex items-center gap-2">
<Music className="size-4" />
<span>{playlist.title}</span>
</div>
</SidebarMenuButton>
{playlist.id === playlistId && (
<SidebarMenuAction
onClick={() => handleDeletePlaylist(playlist.id)}
className="text-red-600 hover:text-red-800"
>
<Trash2 className="size-4" />
<span className="sr-only">Delete {playlist.title}</span>
</SidebarMenuAction>
)}
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
{activeTrack && (
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem className="flex justify-end">
<SidebarMenuButton
onClick={playState.toggle}
aria-label={
isPlaying ? "Pause active track" : "Play active track"
}
>
<div className="w-[28px] h-[28px] flex items-center justify-center bg-blue-600 rounded-full text-white hover:bg-blue-700">
{isPlaying ? (
<Pause size={16} fill="currentColor" />
) : (
<Play size={16} fill="currentColor" />
)}
</div>
<span>{activeTrackTitle}</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
)}
</Sidebar>
);
}

View File

@@ -5,7 +5,7 @@ import * as React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
@@ -53,5 +53,4 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
);
Button.displayName = "Button";
// eslint-disable-next-line react-refresh/only-export-components
export { Button, buttonVariants };

View File

@@ -0,0 +1,29 @@
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import * as React from "react";
import { cn } from "@/lib/utils";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref,
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className,
)}
{...props}
/>
),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator };

View File

@@ -0,0 +1,140 @@
"use client";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { type VariantProps, cva } from "class-variance-authority";
import { X } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"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",
className,
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
},
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

View File

@@ -0,0 +1,779 @@
import { Slot } from "@radix-ui/react-slot";
import { VariantProps, cva } from "class-variance-authority";
import { PanelLeft } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet";
import { Skeleton } from "@/components/ui/skeleton";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
const SIDEBAR_COOKIE_NAME = "sidebar_state";
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
const SIDEBAR_WIDTH = "16rem";
const SIDEBAR_WIDTH_MOBILE = "18rem";
const SIDEBAR_WIDTH_ICON = "3rem";
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
type SidebarContextProps = {
state: "expanded" | "collapsed";
open: boolean;
setOpen: (open: boolean) => void;
openMobile: boolean;
setOpenMobile: (open: boolean) => void;
isMobile: boolean;
toggleSidebar: () => void;
};
const SidebarContext = React.createContext<SidebarContextProps | null>(null);
function useSidebar() {
const context = React.useContext(SidebarContext);
if (!context) {
throw new Error("useSidebar must be used within a SidebarProvider.");
}
return context;
}
const SidebarProvider = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
defaultOpen?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
}
>(
(
{
defaultOpen = true,
open: openProp,
onOpenChange: setOpenProp,
className,
style,
children,
...props
},
ref,
) => {
const isMobile = useIsMobile();
const [openMobile, setOpenMobile] = React.useState(false);
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
const [_open, _setOpen] = React.useState(defaultOpen);
const open = openProp ?? _open;
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
const openState = typeof value === "function" ? value(open) : value;
if (setOpenProp) {
setOpenProp(openState);
} else {
_setOpen(openState);
}
// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
},
[setOpenProp, open],
);
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
return isMobile
? setOpenMobile((open) => !open)
: setOpen((open) => !open);
}, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
(event.metaKey || event.ctrlKey)
) {
event.preventDefault();
toggleSidebar();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [toggleSidebar]);
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
const state = open ? "expanded" : "collapsed";
const contextValue = React.useMemo<SidebarContextProps>(
() => ({
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
}),
[
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
],
);
return (
<SidebarContext.Provider value={contextValue}>
<TooltipProvider delayDuration={0}>
<div
style={
{
"--sidebar-width": SIDEBAR_WIDTH,
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
...style,
} as React.CSSProperties
}
className={cn(
"group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",
className,
)}
ref={ref}
{...props}
>
{children}
</div>
</TooltipProvider>
</SidebarContext.Provider>
);
},
);
SidebarProvider.displayName = "SidebarProvider";
const Sidebar = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
side?: "left" | "right";
variant?: "sidebar" | "floating" | "inset";
collapsible?: "offcanvas" | "icon" | "none";
}
>(
(
{
side = "left",
variant = "sidebar",
collapsible = "offcanvas",
className,
children,
...props
},
ref,
) => {
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
if (collapsible === "none") {
return (
<div
className={cn(
"flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",
className,
)}
ref={ref}
{...props}
>
{children}
</div>
);
}
if (isMobile) {
return (
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
style={
{
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
} as React.CSSProperties
}
side={side}
>
<SheetHeader className="sr-only">
<SheetTitle>Sidebar</SheetTitle>
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
</SheetHeader>
<div className="flex h-full w-full flex-col">{children}</div>
</SheetContent>
</Sheet>
);
}
return (
<div
ref={ref}
className="group peer hidden text-sidebar-foreground md:block"
data-state={state}
data-collapsible={state === "collapsed" ? collapsible : ""}
data-variant={variant}
data-side={side}
>
{/* This is what handles the sidebar gap on desktop */}
<div
className={cn(
"relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear",
"group-data-[collapsible=offcanvas]:w-0",
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
)}
/>
<div
className={cn(
"fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex",
side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
// Adjust the padding for floating and inset variants.
variant === "floating" || variant === "inset"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",
className,
)}
{...props}
>
<div
data-sidebar="sidebar"
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow"
>
{children}
</div>
</div>
</div>
);
},
);
Sidebar.displayName = "Sidebar";
const SidebarTrigger = React.forwardRef<
React.ElementRef<typeof Button>,
React.ComponentProps<typeof Button>
>(({ className, onClick, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<Button
ref={ref}
data-sidebar="trigger"
variant="ghost"
size="icon"
className={cn("h-7 w-7", className)}
onClick={(event) => {
onClick?.(event);
toggleSidebar();
}}
{...props}
>
<PanelLeft />
<span className="sr-only">Toggle Sidebar</span>
</Button>
);
});
SidebarTrigger.displayName = "SidebarTrigger";
const SidebarRail = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button">
>(({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
data-sidebar="rail"
aria-label="Toggle Sidebar"
tabIndex={-1}
onClick={toggleSidebar}
title="Toggle Sidebar"
className={cn(
"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex",
"[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize",
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar",
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
className,
)}
{...props}
/>
);
});
SidebarRail.displayName = "SidebarRail";
const SidebarInset = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"main">
>(({ className, ...props }, ref) => {
return (
<main
ref={ref}
className={cn(
"relative flex w-full flex-1 flex-col bg-background",
"md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
className,
)}
{...props}
/>
);
});
SidebarInset.displayName = "SidebarInset";
const SidebarInput = React.forwardRef<
React.ElementRef<typeof Input>,
React.ComponentProps<typeof Input>
>(({ className, ...props }, ref) => {
return (
<Input
ref={ref}
data-sidebar="input"
className={cn(
"h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
className,
)}
{...props}
/>
);
});
SidebarInput.displayName = "SidebarInput";
const SidebarHeader = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="header"
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
);
});
SidebarHeader.displayName = "SidebarHeader";
const SidebarFooter = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="footer"
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
);
});
SidebarFooter.displayName = "SidebarFooter";
const SidebarSeparator = React.forwardRef<
React.ElementRef<typeof Separator>,
React.ComponentProps<typeof Separator>
>(({ className, ...props }, ref) => {
return (
<Separator
ref={ref}
data-sidebar="separator"
className={cn("mx-2 w-auto bg-sidebar-border", className)}
{...props}
/>
);
});
SidebarSeparator.displayName = "SidebarSeparator";
const SidebarContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="content"
className={cn(
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
className,
)}
{...props}
/>
);
});
SidebarContent.displayName = "SidebarContent";
const SidebarGroup = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="group"
className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
{...props}
/>
);
});
SidebarGroup.displayName = "SidebarGroup";
const SidebarGroupLabel = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "div";
return (
<Comp
ref={ref}
data-sidebar="group-label"
className={cn(
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
className,
)}
{...props}
/>
);
});
SidebarGroupLabel.displayName = "SidebarGroupLabel";
const SidebarGroupAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
ref={ref}
data-sidebar="group-action"
className={cn(
"absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
);
});
SidebarGroupAction.displayName = "SidebarGroupAction";
const SidebarGroupContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
<div
ref={ref}
data-sidebar="group-content"
className={cn("w-full text-sm", className)}
{...props}
/>
));
SidebarGroupContent.displayName = "SidebarGroupContent";
const SidebarMenu = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
data-sidebar="menu"
className={cn("flex w-full min-w-0 flex-col gap-1", className)}
{...props}
/>
));
SidebarMenu.displayName = "SidebarMenu";
const SidebarMenuItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
<li
ref={ref}
data-sidebar="menu-item"
className={cn("group/menu-item relative", className)}
{...props}
/>
));
SidebarMenuItem.displayName = "SidebarMenuItem";
const sidebarMenuButtonVariants = cva(
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
{
variants: {
variant: {
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
outline:
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
},
size: {
default: "h-8 text-sm",
sm: "h-7 text-xs",
lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
const SidebarMenuButton = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
asChild?: boolean;
isActive?: boolean;
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
} & VariantProps<typeof sidebarMenuButtonVariants>
>(
(
{
asChild = false,
isActive = false,
variant = "default",
size = "default",
tooltip,
className,
...props
},
ref,
) => {
const Comp = asChild ? Slot : "button";
const { isMobile, state } = useSidebar();
const button = (
<Comp
ref={ref}
data-sidebar="menu-button"
data-size={size}
data-active={isActive}
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
{...props}
/>
);
if (!tooltip) {
return button;
}
if (typeof tooltip === "string") {
tooltip = {
children: tooltip,
};
}
return (
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent
side="right"
align="center"
hidden={state !== "collapsed" || isMobile}
{...tooltip}
/>
</Tooltip>
);
},
);
SidebarMenuButton.displayName = "SidebarMenuButton";
const SidebarMenuAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
asChild?: boolean;
showOnHover?: boolean;
}
>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
ref={ref}
data-sidebar="menu-action"
className={cn(
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden",
"peer-data-[size=sm]/menu-button:top-1",
"peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden",
showOnHover &&
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",
className,
)}
{...props}
/>
);
});
SidebarMenuAction.displayName = "SidebarMenuAction";
const SidebarMenuBadge = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
<div
ref={ref}
data-sidebar="menu-badge"
className={cn(
"pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground",
"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
"peer-data-[size=sm]/menu-button:top-1",
"peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
));
SidebarMenuBadge.displayName = "SidebarMenuBadge";
const SidebarMenuSkeleton = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
showIcon?: boolean;
}
>(({ className, showIcon = false, ...props }, ref) => {
// Random width between 50 to 90%.
const width = React.useMemo(() => {
return `${Math.floor(Math.random() * 40) + 50}%`;
}, []);
return (
<div
ref={ref}
data-sidebar="menu-skeleton"
className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
{...props}
>
{showIcon && (
<Skeleton
className="size-4 rounded-md"
data-sidebar="menu-skeleton-icon"
/>
)}
<Skeleton
className="h-4 max-w-[--skeleton-width] flex-1"
data-sidebar="menu-skeleton-text"
style={
{
"--skeleton-width": width,
} as React.CSSProperties
}
/>
</div>
);
});
SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton";
const SidebarMenuSub = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
data-sidebar="menu-sub"
className={cn(
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
));
SidebarMenuSub.displayName = "SidebarMenuSub";
const SidebarMenuSubItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ ...props }, ref) => <li ref={ref} {...props} />);
SidebarMenuSubItem.displayName = "SidebarMenuSubItem";
const SidebarMenuSubButton = React.forwardRef<
HTMLAnchorElement,
React.ComponentProps<"a"> & {
asChild?: boolean;
size?: "sm" | "md";
isActive?: boolean;
}
>(({ asChild = false, size = "md", isActive, className, ...props }, ref) => {
const Comp = asChild ? Slot : "a";
return (
<Comp
ref={ref}
data-sidebar="menu-sub-button"
data-size={size}
data-active={isActive}
className={cn(
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
size === "sm" && "text-xs",
size === "md" && "text-sm",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
);
});
SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
export {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarInput,
SidebarInset,
SidebarMenu,
SidebarMenuAction,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSkeleton,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
SidebarRail,
SidebarSeparator,
SidebarTrigger,
useSidebar,
};

View File

@@ -0,0 +1,15 @@
import { cn } from "@/lib/utils";
function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-muted", className)}
{...props}
/>
);
}
export { Skeleton };

View File

@@ -1,5 +1,3 @@
"use client";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import * as React from "react";
@@ -19,7 +17,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
className,
)}
{...props}

View File

@@ -0,0 +1,21 @@
import * as React from "react";
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
undefined,
);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener("change", onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener("change", onChange);
}, []);
return !!isMobile;
}

View File

@@ -33,6 +33,22 @@
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
@@ -63,6 +79,14 @@
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--ring: 24 5.7% 82.9%;
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}

View File

@@ -52,6 +52,16 @@ const config: Config = {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
sidebar: {
DEFAULT: "hsl(var(--sidebar-background))",
foreground: "hsl(var(--sidebar-foreground))",
primary: "hsl(var(--sidebar-primary))",
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
accent: "hsl(var(--sidebar-accent))",
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
border: "hsl(var(--sidebar-border))",
ring: "hsl(var(--sidebar-ring))",
},
},
borderRadius: {
lg: "var(--radius)",
@@ -60,12 +70,20 @@ const config: Config = {
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
from: {
height: "0",
},
to: {
height: "var(--radix-accordion-content-height)",
},
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
from: {
height: "var(--radix-accordion-content-height)",
},
to: {
height: "0",
},
},
},
animation: {

View File

@@ -71,7 +71,7 @@ export class HomePage {
async navigateToPlaylist(playlistTitle: string) {
await this.page
.getByRole("link", {
.getByRole("button", {
name: playlistTitle,
})
.click();
@@ -79,7 +79,7 @@ export class HomePage {
async navigateToHome() {
await this.page
.getByRole("link", {
.getByRole("button", {
name: "All tracks",
})
.click();

View File

@@ -1,5 +1,58 @@
# organization
## 0.0.108
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.107
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.106
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.105
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.104
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.103
### Patch Changes
- jazz-react@0.14.13
## 0.0.102
### Patch Changes
- jazz-react@0.14.12
## 0.0.101
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.101",
"version": "0.0.108",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,45 @@
# passkey-svelte
## 0.0.102
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-svelte@0.14.18
## 0.0.101
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-svelte@0.14.17
## 0.0.100
### Patch Changes
- jazz-svelte@0.14.16
- jazz-tools@0.14.16
## 0.0.99
### Patch Changes
- jazz-svelte@0.14.15
- jazz-tools@0.14.15
## 0.0.98
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-svelte@0.14.14
## 0.0.97
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "passkey-svelte",
"version": "0.0.97",
"version": "0.0.102",
"type": "module",
"private": true,
"scripts": {

View File

@@ -1,5 +1,58 @@
# minimal-auth-passkey
## 0.0.113
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.112
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.111
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.110
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.109
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.108
### Patch Changes
- jazz-react@0.14.13
## 0.0.107
### Patch Changes
- jazz-react@0.14.12
## 0.0.106
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passkey",
"private": true,
"version": "0.0.106",
"version": "0.0.113",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,58 @@
# passphrase
## 0.0.110
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.109
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.108
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.107
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.106
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.105
### Patch Changes
- jazz-react@0.14.13
## 0.0.104
### Patch Changes
- jazz-react@0.14.12
## 0.0.103
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "passphrase",
"private": true,
"version": "0.0.103",
"version": "0.0.110",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,58 @@
# jazz-password-manager
## 0.0.134
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.133
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.132
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.131
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.130
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.129
### Patch Changes
- jazz-react@0.14.13
## 0.0.128
### Patch Changes
- jazz-react@0.14.12
## 0.0.127
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.127",
"version": "0.0.134",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,58 @@
# jazz-example-pets
## 0.0.232
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.231
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.230
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.229
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.228
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.227
### Patch Changes
- jazz-react@0.14.13
## 0.0.226
### Patch Changes
- jazz-react@0.14.12
## 0.0.225
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-pets",
"private": true,
"version": "0.0.225",
"version": "0.0.232",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,58 @@
# reactions
## 0.0.112
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.111
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.110
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.109
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.108
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.107
### Patch Changes
- jazz-react@0.14.13
## 0.0.106
### Patch Changes
- jazz-react@0.14.12
## 0.0.105
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "reactions",
"private": true,
"version": "0.0.105",
"version": "0.0.112",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,63 @@
# richtext-tiptap
## 0.1.25
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
- jazz-richtext-tiptap@0.14.18
## 0.1.24
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
- jazz-richtext-tiptap@0.1.22
## 0.1.23
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
- jazz-richtext-tiptap@0.1.21
## 0.1.22
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
- jazz-richtext-tiptap@0.1.20
## 0.1.21
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
- jazz-richtext-tiptap@0.1.19
## 0.1.20
### Patch Changes
- jazz-react@0.14.13
## 0.1.19
### Patch Changes
- jazz-react@0.14.12
## 0.1.18
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "richtext-tiptap",
"private": true,
"version": "0.1.18",
"version": "0.1.25",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,63 @@
# richtext
## 0.0.102
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
- jazz-richtext-prosemirror@0.14.18
## 0.0.101
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
- jazz-richtext-prosemirror@0.1.33
## 0.0.100
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
- jazz-richtext-prosemirror@0.1.32
## 0.0.99
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
- jazz-richtext-prosemirror@0.1.31
## 0.0.98
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
- jazz-richtext-prosemirror@0.1.30
## 0.0.97
### Patch Changes
- jazz-react@0.14.13
## 0.0.96
### Patch Changes
- jazz-react@0.14.12
## 0.0.95
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "richtext",
"private": true,
"version": "0.0.95",
"version": "0.0.102",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,50 @@
# todo-vue
## 0.0.114
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-browser@0.14.18
- jazz-vue@0.14.18
## 0.0.113
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-browser@0.14.17
- jazz-vue@0.14.17
## 0.0.112
### Patch Changes
- jazz-browser@0.14.16
- jazz-tools@0.14.16
- jazz-vue@0.14.16
## 0.0.111
### Patch Changes
- jazz-browser@0.14.15
- jazz-tools@0.14.15
- jazz-vue@0.14.15
## 0.0.110
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-browser@0.14.14
- jazz-vue@0.14.14
## 0.0.109
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "todo-vue",
"version": "0.0.109",
"version": "0.0.114",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,58 @@
# jazz-example-todo
## 0.0.231
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-react@0.14.18
## 0.0.230
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-react@0.14.17
## 0.0.229
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.228
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.227
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.226
### Patch Changes
- jazz-react@0.14.13
## 0.0.225
### Patch Changes
- jazz-react@0.14.12
## 0.0.224
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-todo",
"private": true,
"version": "0.0.224",
"version": "0.0.231",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1,5 +1,65 @@
# version-history
## 0.0.110
### Patch Changes
- Updated dependencies [4b950bc]
- Updated dependencies [d6d9c0a]
- Updated dependencies [c559054]
- jazz-tools@0.14.18
- jazz-inspector@0.14.18
- jazz-react@0.14.18
## 0.0.109
### Patch Changes
- Updated dependencies [e512df4]
- jazz-tools@0.14.17
- jazz-inspector@0.14.17
- jazz-react@0.14.17
## 0.0.108
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.107
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.106
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.105
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.104
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.103
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "version-history",
"private": true,
"version": "0.0.103",
"version": "0.0.110",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -72,7 +72,7 @@ export const team: Array<TeamMember> = [
{
name: "Emil Sayahi",
titles: ["Full-Stack Dev", "Support Dev"],
location: "Oxford, Ohio, US",
location: "San Francisco, California, US",
github: "emmyoh",
linkedin: "emil-sayahi",
bluesky: "sayahi.bsky.social",

View File

@@ -17,6 +17,7 @@ export default function Home() {
<HeroSection />
<div className="container flex flex-col gap-12 mt-12 lg:gap-20 lg:mt-20">
<SupportedEnvironmentsSection />
<HowJazzWorksSection />
<Testimonial name="Spreadsheet app (stealth)" role="CTO">
@@ -51,8 +52,6 @@ export default function Home() {
<FeaturesSection />
<SupportedEnvironmentsSection />
<ComingSoonSection />
<EarlyAdopterSection />

View File

@@ -3,7 +3,7 @@ import { ThemeProvider } from "@/components/ThemeProvider";
import { JazzFooter } from "@/components/footer";
import { marketingCopy } from "@/content/marketingCopy";
import { fontClasses } from "@garden-co/design-system/src/fonts";
import { Analytics } from "@vercel/analytics/react";
import { Analytics } from "@vercel/analytics/next";
import { SpeedInsights } from "@vercel/speed-insights/next";
import type { Metadata } from "next";

View File

@@ -145,7 +145,7 @@ export function FeaturesSection() {
<Prose size="sm">
or{" "}
<Link href="/docs/sync-and-storage#running-your-own">
<Link href="/docs/react/sync-and-storage#running-your-own-sync-server">
self-host
</Link>
.

View File

@@ -1,95 +1,118 @@
import { KotlinLogo } from "@/components/icons/KotlinLogo";
import { BunLogo } from "@/components/icons/BunLogo";
import { CloudflareWorkerLogo } from "@/components/icons/CloudflareWorkerLogo";
import { ExpoLogo } from "@/components/icons/ExpoLogo";
import { JavascriptLogo } from "@/components/icons/JavascriptLogo";
import { NodejsLogo } from "@/components/icons/NodejsLogo";
import { ReactLogo } from "@/components/icons/ReactLogo";
import { ReactNativeLogo } from "@/components/icons/ReactNativeLogo";
import { RustLogo } from "@/components/icons/RustLogo";
import { SvelteLogo } from "@/components/icons/SvelteLogo";
import { SwiftLogo } from "@/components/icons/SwiftLogo";
import { VueLogo } from "@/components/icons/VueLogo";
import { Icon } from "@garden-co/design-system/src/components/atoms/Icon";
import { GappedGrid } from "@garden-co/design-system/src/components/molecules/GappedGrid";
import React from "react";
export function SupportedEnvironmentsSection() {
const supported = [
const frameworks = [
{
name: "Browser (vanilla JS)",
icon: (
<Icon
name="browser"
size="3xl"
className="text-highlight"
height="1em"
width="1em"
/>
),
name: "JavaScript",
icon: JavascriptLogo,
},
{
name: "React",
icon: <ReactLogo />,
icon: ReactLogo,
},
{
name: "React Native",
icon: <ReactNativeLogo />,
icon: ReactNativeLogo,
},
{
name: "Vue",
icon: <VueLogo />,
name: "Expo",
icon: ExpoLogo,
},
{
name: "Svelte",
icon: <SvelteLogo />,
},
{
name: "Node.js",
icon: <NodejsLogo />,
icon: SvelteLogo,
},
];
const comingSoon = [
const serverWorkers = [
{
name: "Swift",
icon: <SwiftLogo />,
name: "Node.js",
icon: NodejsLogo,
},
{
name: "Rust",
icon: <RustLogo className="text-black dark:text-white" />,
name: "Cloudflare Workers",
icon: CloudflareWorkerLogo,
},
{
name: "Kotlin",
icon: <KotlinLogo />,
name: "Bun",
icon: BunLogo,
},
];
const first = [
{
name: "JavaScript",
icon: JavascriptLogo,
},
{
name: "React",
icon: ReactLogo,
},
{
name: "Svelte",
icon: SvelteLogo,
},
{
name: "Expo",
icon: ExpoLogo,
},
{
name: "React Native",
icon: ReactNativeLogo,
},
];
const second = [
{
name: "Node.js",
icon: NodejsLogo,
},
{
name: "Cloudflare Workers",
icon: CloudflareWorkerLogo,
},
{
name: "Bun",
icon: BunLogo,
},
];
return (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3 lg:gap-8">
<h2 className="font-semibold tracking-tight font-display text-2xl text-stone-900 lg:text-balance sm:text-4xl dark:text-white">
Jazz works with your favorite stack
</h2>
<div className="flex flex-col gap-6 lg:col-span-2 lg:gap-8">
<div className="flex flex-col gap-5 lg:flex-row lg:gap-8">
{supported.map((tech) => (
<div key={tech.name} className="flex items-center gap-2">
<span className="text-xl">{tech.icon}</span>
<div className="text-center font-medium text-highlight lg:text-lg">
{tech.name}
</div>
</div>
))}
</div>
<div className="flex flex-col gap-3">
<p className="text-sm">Coming soon</p>
<div className="flex gap-x-5 gap-y-3 flex-wrap">
{comingSoon.map((tech) => (
<div key={tech.name} className="flex items-center gap-2">
<span className="text-xl">{tech.icon}</span>
<div className="text-center text-sm text-highlight">
{tech.name}
<>
<h2 className="sr-only">Supported environments</h2>
<GappedGrid>
{[
{
label: "Build apps with",
items: frameworks,
},
{
label: "Optionally add server workers",
items: serverWorkers,
},
].map(({ label, items }) => (
<div className="col-span-2 lg:col-span-3" key={label}>
<h3 className="mb-4 text-highlight font-medium">{label}</h3>
<div className="flex gap-x-6 gap-y-3 grayscale flex-col lg:flex-row">
{items.map(({ name, icon: Icon }) => (
<div key={name} className="flex items-center gap-2">
<Icon className="size-6" />
{name}
</div>
</div>
))}
))}
</div>
</div>
</div>
</div>
</div>
))}
</GappedGrid>
</>
);
}

View File

@@ -0,0 +1,75 @@
export function BunLogo(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
width="1em"
height="1em"
{...props}
viewBox="0 0 435 435"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M384.167 143.033C383.348 142.139 382.477 141.246 381.606 140.405C380.735 139.563 379.916 138.617 379.045 137.776C378.174 136.935 377.354 135.989 376.483 135.147C375.613 134.306 374.793 133.36 373.922 132.519C373.051 131.678 372.232 130.731 371.361 129.89C370.49 129.049 369.67 128.103 368.799 127.262C367.929 126.421 367.109 125.474 366.238 124.633C391.647 150.26 406.204 185.123 406.758 221.68C406.758 308.791 320.596 379.657 214.66 379.657C155.34 379.657 102.269 357.419 66.9745 322.565L69.5358 325.193L72.0971 327.822L74.6584 330.45L77.2197 333.079L79.781 335.707L82.3424 338.336L84.9037 340.965C120.147 377.291 174.396 400.686 235.15 400.686C341.086 400.686 427.249 329.819 427.249 242.971C427.249 205.856 411.676 170.686 384.167 143.033Z"
fill="black"
/>
<path
d="M393.951 221.68C393.951 301.641 313.68 366.462 214.66 366.462C115.639 366.462 35.3678 301.641 35.3678 221.68C35.3678 172.105 66.1035 128.313 113.334 102.343C160.565 76.3726 189.969 49.7714 214.66 49.7714C239.351 49.7714 260.456 71.4834 315.985 102.343C363.216 128.313 393.951 172.105 393.951 221.68Z"
fill="#FBF0DF"
/>
<path
d="M393.951 221.68C393.926 211.408 392.548 201.187 389.853 191.294C375.868 366.356 167.788 374.768 85.9794 322.407C122.755 351.659 168.136 367.196 214.66 366.462C313.526 366.462 393.951 301.536 393.951 221.68Z"
fill="#F6DECE"
/>
<path
d="M145.658 92.7223C168.556 78.6332 198.984 52.1897 228.901 52.1372C224.298 50.6105 219.496 49.8127 214.66 49.7714C202.263 49.7714 189.047 56.3429 172.398 66.2263C166.609 69.696 160.616 73.5337 154.264 77.5292C142.328 85.0994 128.651 93.6686 113.283 102.238C64.5155 129.312 35.3678 173.945 35.3678 221.68C35.3678 223.783 35.3678 225.886 35.3678 227.936C66.4109 115.381 122.811 106.811 145.658 92.7223Z"
fill="#FFFEFC"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M199.906 63.072C199.978 75.4853 197.439 87.7682 192.461 99.0821C187.484 110.396 180.186 120.474 171.066 128.629C169.632 129.943 170.759 132.466 172.603 131.73C189.866 124.843 213.174 104.235 203.339 62.6514C202.929 60.2857 199.906 60.9166 199.906 63.072ZM211.535 63.072C217.803 73.5675 221.785 85.3299 223.208 97.5527C224.632 109.776 223.463 122.17 219.782 133.886C219.167 135.726 221.37 137.303 222.6 135.778C233.818 121.058 243.602 91.8286 214.301 60.2857C212.815 58.9189 210.51 61.0217 211.535 62.8617V63.072ZM225.673 62.1783C235.489 69.3099 243.7 78.5187 249.753 89.1837C255.807 99.8487 259.561 111.722 260.763 124.002C260.711 124.445 260.827 124.891 261.087 125.248C261.347 125.605 261.731 125.846 262.159 125.92C262.588 125.994 263.027 125.897 263.387 125.647C263.747 125.398 264 125.016 264.093 124.581C268.806 106.233 266.142 74.9531 227.364 58.7086C225.315 57.8674 223.983 60.7063 225.673 61.968V62.1783ZM131.11 116.853C142.785 113.273 153.596 107.209 162.837 99.0574C172.078 90.9054 179.542 80.8474 184.743 69.5383C185.666 67.6457 188.585 68.3817 188.124 70.4846C179.262 112.542 149.602 121.321 131.161 120.165C129.214 120.217 129.266 117.431 131.11 116.853Z"
fill="#CCBEA7"
/>
<path
d="M214.66 379.657C108.724 379.657 22.5613 308.791 22.5613 221.68C22.5613 169.109 54.2191 120.059 107.238 90.672C122.606 82.2606 135.771 73.7966 147.502 66.384C153.957 62.2834 160.052 58.4457 165.944 54.8709C183.924 43.936 199.292 36.6286 214.66 36.6286C230.028 36.6286 243.449 42.9371 260.251 53.136C265.374 56.1326 270.496 59.392 275.977 62.9669C288.733 71.0629 303.127 80.2103 322.081 90.672C375.1 120.059 406.758 169.056 406.758 221.68C406.758 308.791 320.596 379.657 214.66 379.657ZM214.66 49.7714C202.263 49.7714 189.047 56.3429 172.398 66.2263C166.609 69.696 160.616 73.5337 154.264 77.5292C142.328 85.0995 128.651 93.6686 113.283 102.238C64.5156 129.312 35.3678 173.945 35.3678 221.68C35.3678 301.536 115.793 366.515 214.66 366.515C313.526 366.515 393.951 301.536 393.951 221.68C393.951 173.945 364.804 129.312 315.985 102.343C296.622 91.8286 281.51 81.9452 269.267 74.1646C263.683 70.6423 258.561 67.3829 253.899 64.4914C238.377 55.0286 227.056 49.7714 214.66 49.7714Z"
fill="black"
/>
<path
d="M250.774 260.057C248.473 269.73 243.234 278.401 235.816 284.818C230.246 290.359 223.036 293.837 215.325 294.702C207.383 293.974 199.92 290.487 194.169 284.818C186.826 278.371 181.662 269.703 179.416 260.057C179.341 259.485 179.396 258.902 179.575 258.354C179.753 257.806 180.052 257.308 180.448 256.897C180.843 256.486 181.325 256.173 181.857 255.983C182.388 255.793 182.955 255.73 183.514 255.799H246.727C247.282 255.738 247.843 255.808 248.368 256.002C248.893 256.196 249.368 256.51 249.758 256.92C250.147 257.33 250.441 257.825 250.617 258.369C250.793 258.912 250.847 259.489 250.774 260.057V260.057Z"
fill="#B71422"
/>
<path
d="M194.169 285.239C199.908 290.911 207.344 294.431 215.274 295.227C223.186 294.419 230.603 290.901 236.328 285.239C238.16 283.487 239.871 281.607 241.451 279.614C238.295 275.94 234.44 272.967 230.124 270.879C225.807 268.79 221.12 267.63 216.35 267.47C211.246 267.594 206.249 268.989 201.787 271.535C197.325 274.081 193.533 277.701 190.737 282.085C191.915 283.189 192.94 284.24 194.169 285.239Z"
fill="#FF6164"
/>
<path
d="M194.989 281.086C197.528 277.717 200.779 274.982 204.497 273.088C208.215 271.195 212.302 270.19 216.453 270.151C224.124 270.383 231.433 273.552 236.943 279.035C238.121 277.721 239.248 276.354 240.324 274.987C233.807 268.618 225.195 264.996 216.196 264.841C211.388 264.884 206.648 266.018 202.317 268.163C197.986 270.308 194.171 273.411 191.147 277.248C192.358 278.598 193.641 279.88 194.989 281.086V281.086Z"
fill="black"
/>
<path
d="M215.121 297.856C206.585 297.089 198.552 293.383 192.325 287.342C184.395 280.459 178.814 271.158 176.394 260.793C176.22 259.871 176.25 258.92 176.48 258.01C176.71 257.101 177.136 256.255 177.726 255.536C178.428 254.666 179.314 253.972 180.317 253.508C181.321 253.043 182.414 252.82 183.514 252.855H246.727C247.826 252.831 248.916 253.06 249.917 253.524C250.919 253.987 251.806 254.675 252.516 255.536C253.1 256.258 253.518 257.105 253.74 258.015C253.961 258.925 253.981 259.875 253.796 260.793C251.376 271.158 245.795 280.459 237.865 287.342C231.652 293.373 223.639 297.077 215.121 297.856ZM183.514 258.953C182.694 258.953 182.49 259.321 182.438 259.426C184.604 268.414 189.502 276.461 196.423 282.4C201.484 287.517 208.064 290.755 215.121 291.6C222.159 290.764 228.732 287.567 233.818 282.505C240.718 276.556 245.597 268.511 247.752 259.532C247.64 259.363 247.485 259.23 247.304 259.147C247.124 259.063 246.924 259.033 246.727 259.058L183.514 258.953Z"
fill="black"
/>
<path
d="M292.626 263.317C309.177 263.317 322.593 255.22 322.593 245.232C322.593 235.244 309.177 227.147 292.626 227.147C276.076 227.147 262.659 235.244 262.659 245.232C262.659 255.22 276.076 263.317 292.626 263.317Z"
fill="#FEBBD0"
/>
<path
d="M137.564 263.317C154.115 263.317 167.532 255.22 167.532 245.232C167.532 235.244 154.115 227.147 137.564 227.147C121.014 227.147 107.597 235.244 107.597 245.232C107.597 255.22 121.014 263.317 137.564 263.317Z"
fill="#FEBBD0"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M151.651 237.977C157.236 237.988 162.698 236.298 167.347 233.121C171.995 229.944 175.621 225.424 177.765 220.132C179.909 214.84 180.476 209.014 179.392 203.391C178.309 197.769 175.625 192.603 171.679 188.546C167.734 184.49 162.705 181.726 157.228 180.604C151.751 179.482 146.074 180.053 140.913 182.243C135.753 184.434 131.341 188.147 128.238 192.912C125.134 197.676 123.477 203.279 123.477 209.01C123.477 216.684 126.444 224.044 131.726 229.474C137.008 234.905 144.174 237.963 151.651 237.977V237.977ZM278.539 237.977C284.13 238.019 289.607 236.355 294.276 233.198C298.944 230.04 302.594 225.531 304.762 220.242C306.929 214.953 307.518 209.122 306.452 203.489C305.386 197.856 302.714 192.675 298.775 188.603C294.836 184.531 289.807 181.751 284.326 180.616C278.845 179.482 273.16 180.043 267.99 182.229C262.821 184.415 258.4 188.128 255.29 192.896C252.179 197.664 250.518 203.272 250.518 209.01C250.504 216.661 253.446 224.005 258.698 229.434C263.95 234.864 271.084 237.935 278.539 237.977V237.977Z"
fill="black"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M142.943 210.85C145.042 210.861 147.098 210.231 148.848 209.042C150.599 207.852 151.966 206.157 152.776 204.169C153.587 202.182 153.804 199.992 153.401 197.877C152.997 195.763 151.991 193.819 150.51 192.292C149.029 190.765 147.14 189.723 145.082 189.299C143.023 188.875 140.889 189.087 138.948 189.909C137.008 190.731 135.349 192.126 134.181 193.917C133.014 195.707 132.39 197.813 132.39 199.968C132.39 202.845 133.5 205.605 135.478 207.644C137.456 209.684 140.14 210.836 142.943 210.85ZM269.83 210.85C271.93 210.861 273.985 210.231 275.735 209.042C277.486 207.852 278.853 206.157 279.664 204.169C280.474 202.182 280.691 199.992 280.288 197.877C279.885 195.763 278.879 193.819 277.398 192.292C275.917 190.765 274.028 189.723 271.969 189.299C269.911 188.875 267.776 189.087 265.836 189.909C263.895 190.731 262.236 192.126 261.068 193.917C259.901 195.707 259.278 197.813 259.278 199.968C259.278 202.827 260.374 205.571 262.329 207.608C264.285 209.644 266.942 210.809 269.728 210.85H269.83Z"
fill="white"
/>
</svg>
);
}

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