Compare commits

..

4 Commits

Author SHA1 Message Date
Guido D'Orsi
9ea7d8906b chore: update lockfile 2024-12-18 11:42:42 +01:00
Guido D'Orsi
8c42eea0e6 Merge branch 'main' into feat/quick-crypto 2024-12-18 11:41:24 +01:00
Guido D'Orsi
551b02bbe3 Merge remote-tracking branch 'origin/main' into feat/quick-crypto 2024-12-18 11:26:24 +01:00
Brad Anderson
a5fe660529 feat: add react-native-quick-crypto for ed25519 2024-12-14 23:18:38 -05:00
342 changed files with 7064 additions and 16500 deletions

View File

@@ -0,0 +1,5 @@
---
"cojson": patch
---
Remove @opentelemetry/api as a peer dependency and add it as a dependency

View File

@@ -1,52 +0,0 @@
name: Build Starters
on:
push:
branches: [ "main" ]
jobs:
build-starters:
runs-on: ubuntu-latest
strategy:
matrix:
starter: [
"react-demo-auth-tailwind",
]
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Enable corepack
run: corepack enable
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Pnpm Build
run: |
pnpm install
pnpm turbo build;
working-directory: ./starters/${{ matrix.starter }}

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/form", "examples/music-player", "examples/pets", "examples/onboarding"]
project: ["tests/e2e", "examples/chat", "examples/file-share-svelte", "examples/music-player", "examples/pets", "examples/onboarding"]
steps:
- uses: actions/checkout@v3
@@ -45,6 +45,10 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Setup .env
run: echo "VITE_WS_PEER=ws://localhost:4200/" >> .env
working-directory: ./${{ matrix.project }}
- name: Pnpm Build
run: pnpm turbo build
working-directory: ./${{ matrix.project }}

View File

@@ -4,13 +4,6 @@ on:
push:
branches:
- main
workflow_dispatch:
inputs:
debug_enabled:
type: boolean
description: "Run tmate session for debugging"
required: false
default: false
concurrency: ${{ github.workflow }}-${{ github.ref }}
@@ -55,11 +48,4 @@ jobs:
publish: pnpm release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# Enable tmate debugging only if the workflow is manually triggered, debug_enabled is true, and the workflow failed
- name: Setup tmate session for debugging
if: ${{ failure() && github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
uses: mxschmitt/action-tmate@v3
with:
timeout-minutes: 15
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -1,68 +1,5 @@
# jazz-example-book-shelf
## 0.1.39
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-browser-media-images@0.8.51
- jazz-react@0.8.51
## 0.1.38
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
- jazz-browser-media-images@0.8.50
## 0.1.37
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
- jazz-browser-media-images@0.8.49
## 0.1.36
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-browser-media-images@0.8.48
- jazz-react@0.8.48
## 0.1.35
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45
- jazz-browser-media-images@0.8.45
## 0.1.34
### Patch Changes
- jazz-react@0.8.44
- jazz-tools@0.8.44
- jazz-browser-media-images@0.8.44
## 0.1.33
### Patch Changes
- jazz-react@0.8.41
- jazz-tools@0.8.41
- jazz-browser-media-images@0.8.41
## 0.1.32
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "jazz-example-book-shelf",
"version": "0.1.39",
"version": "0.1.32",
"private": true,
"scripts": {
"dev": "next dev",
@@ -11,9 +11,9 @@
},
"dependencies": {
"clsx": "^2.0.0",
"jazz-browser-media-images": "workspace:0.8.51",
"jazz-react": "workspace:0.8.51",
"jazz-tools": "workspace:0.8.51",
"jazz-browser-media-images": "workspace:0.8.40",
"jazz-react": "workspace:0.8.40",
"jazz-tools": "workspace:0.8.39",
"next": "14.2.5",
"react": "^18.3.1",
"react-dom": "^18.3.1"
@@ -23,7 +23,7 @@
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2"
}
}

View File

@@ -31,5 +31,7 @@ export class JazzAccount extends Account {
/** The account migration is run on account creation and on every log-in.
* You can use it to set up the account root and any other initial CoValues you need.
*/
migrate() {}
migrate(this: JazzAccount, creationProps?: { name: string }) {
super.migrate(creationProps);
}
}

View File

@@ -1,100 +1,5 @@
# chat-rn-clerk
## 1.0.41
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react-native@0.8.51
- jazz-react-native-auth-clerk@0.8.51
- jazz-react-native-media-images@0.8.51
## 1.0.40
### Patch Changes
- jazz-react-native@0.8.50
- jazz-react-native-auth-clerk@0.8.50
- jazz-tools@0.8.50
- jazz-react-native-media-images@0.8.50
## 1.0.39
### Patch Changes
- jazz-react-native@0.8.49
- jazz-react-native-auth-clerk@0.8.49
- jazz-tools@0.8.49
- jazz-react-native-media-images@0.8.49
## 1.0.38
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react-native@0.8.48
- jazz-react-native-auth-clerk@0.8.48
- jazz-react-native-media-images@0.8.48
## 1.0.37
### Patch Changes
- Updated dependencies [33ef9c4]
- jazz-react-native@0.8.47
- jazz-react-native-auth-clerk@0.8.47
## 1.0.36
### Patch Changes
- Updated dependencies [ab4ffbd]
- jazz-react-native@0.8.46
- jazz-react-native-auth-clerk@0.8.46
## 1.0.35
### Patch Changes
- Updated dependencies [7701307]
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-react-native@0.8.45
- jazz-tools@0.8.45
- jazz-react-native-auth-clerk@0.8.45
- jazz-react-native-media-images@0.8.45
## 1.0.34
### Patch Changes
- jazz-react-native@0.8.44
- jazz-react-native-auth-clerk@0.8.44
- jazz-tools@0.8.44
- jazz-react-native-media-images@0.8.44
## 1.0.33
### Patch Changes
- cdc7f9f: Fixing react-native examples
- Updated dependencies [cdc7f9f]
- jazz-react-native-auth-clerk@0.8.43
## 1.0.32
### Patch Changes
- jazz-react-native@0.8.41
- jazz-react-native-auth-clerk@0.8.41
- jazz-tools@0.8.41
- jazz-react-native-media-images@0.8.41
## 1.0.31
### Patch Changes

View File

@@ -1,4 +1,3 @@
import "../global.css";
import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo";
import { useFonts } from "expo-font";
import { Slot } from "expo-router";

View File

@@ -1,9 +1,7 @@
module.exports = function (api) {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
presets: ["babel-preset-expo"],
plugins: ["nativewind/babel"],
};
};

View File

@@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,6 +1,5 @@
// Learn more https://docs.expo.dev/guides/monorepos
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const { FileStore } = require("metro-cache");
const path = require("path");
@@ -32,5 +31,4 @@ config.cacheStores = [
}),
];
// module.exports = config;
module.exports = withNativeWind(config, { input: "./global.css" });
module.exports = config;

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.41",
"version": "1.0.31",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
@@ -45,7 +45,7 @@
"jazz-react-native-auth-clerk": "workspace:*",
"jazz-react-native-media-images": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^4.1.21",
"nativewind": "^2.0.11",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-native": "~0.76.3",
@@ -70,7 +70,7 @@
"jest": "^29.2.1",
"jest-expo": "~52.0.2",
"react-test-renderer": "18.2.0",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2"
},
"private": true

View File

@@ -1,14 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all of your component files.
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -0,0 +1,15 @@
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};
export default config;

View File

@@ -7,5 +7,5 @@
"@/*": ["./*"]
}
},
"include": ["**/*.ts", "**/*.tsx", "nativewind-env.d.ts"]
"include": ["**/*.ts", "**/*.tsx"]
}

View File

@@ -1,76 +1,5 @@
# chat-rn
## 1.0.38
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react-native@0.8.51
## 1.0.37
### Patch Changes
- jazz-react-native@0.8.50
- jazz-tools@0.8.50
## 1.0.36
### Patch Changes
- jazz-react-native@0.8.49
- jazz-tools@0.8.49
## 1.0.35
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react-native@0.8.48
## 1.0.34
### Patch Changes
- Updated dependencies [33ef9c4]
- jazz-react-native@0.8.47
## 1.0.33
### Patch Changes
- Updated dependencies [ab4ffbd]
- jazz-react-native@0.8.46
## 1.0.32
### Patch Changes
- Updated dependencies [7701307]
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-react-native@0.8.45
- jazz-tools@0.8.45
## 1.0.31
### Patch Changes
- jazz-react-native@0.8.44
- jazz-tools@0.8.44
## 1.0.30
### Patch Changes
- jazz-react-native@0.8.41
- jazz-tools@0.8.41
## 1.0.29
### Patch Changes

View File

@@ -1,9 +1,7 @@
module.exports = function (api) {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
presets: ["babel-preset-expo"],
plugins: ["nativewind/babel"],
};
};

View File

@@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,6 +1,5 @@
// Learn more https://docs.expo.dev/guides/monorepos
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const { FileStore } = require("metro-cache");
const path = require("path");
@@ -8,7 +7,7 @@ const path = require("path");
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, "../..");
const config = getDefaultConfig(projectRoot, { isCSSEnabled: true });
const config = getDefaultConfig(projectRoot);
// Since we are using pnpm, we have to setup the monorepo manually for Metro
// #1 - Watch all files in the monorepo
@@ -20,10 +19,7 @@ config.resolver.nodeModulesPaths = [
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,
];
config.resolver.requireCycleIgnorePatterns = [/(^|\/|\\)node_modules($|\/|\\)/];
// Use turborepo to restore the cache when possible
config.cacheStores = [
@@ -32,5 +28,4 @@ config.cacheStores = [
}),
];
// module.exports = config;
module.exports = withNativeWind(config, { input: "./global.css" });
module.exports = config;

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.38",
"version": "1.0.29",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
@@ -30,7 +30,7 @@
"expo-web-browser": "~14.0.1",
"jazz-react-native": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^4.1.21",
"nativewind": "^2.0.11",
"react": "^18.3.1",
"react-native": "~0.76.3",
"react-native-fetch-api": "^3.0.0",
@@ -45,7 +45,7 @@
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "^18.3.12",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2"
},
"private": true

View File

@@ -1,5 +1,3 @@
import "../global.css";
import {
NavigationContainer,
useNavigationContainerRef,

View File

@@ -19,35 +19,45 @@ import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
const [chatId, setChatId] = useState<ID<Chat>>();
const loadedChat = useCoState(Chat, chatId, [{}]);
const [chat, setChat] = useState<Chat>();
const [message, setMessage] = useState("");
const loadedChat = useCoState(Chat, chat?.id, [{}]);
useEffect(() => {
navigation.setOptions({
headerRight: () => <Button onPress={logOut} title="Logout" />,
headerLeft: () =>
loadedChat ? (
chat ? (
<Button
onPress={() => {
if (loadedChat?.id) {
if (chat?.id) {
Clipboard.setStringAsync(
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
`https://chat.jazz.tools/#/chat/${chat.id}`,
);
Alert.alert("Copied to clipboard", `Chat ID: ${loadedChat.id}`);
Alert.alert("Copied to clipboard", `Chat ID: ${chat.id}`);
}
}}
title="Share"
/>
) : null,
});
}, [navigation, loadedChat]);
}, [navigation, chat]);
const createChat = () => {
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
setChatId(chat.id);
setChat(chat);
};
const loadChat = async (chatId: ID<Chat>) => {
try {
const chat = await Chat.load(chatId, me, []);
setChat(chat);
} catch (error) {
console.log("Error loading chat", error);
Alert.alert("Error", `Error loading chat: ${error}`);
}
};
const joinChat = () => {
@@ -63,7 +73,7 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
text: "Join",
onPress: (chatId) => {
if (chatId) {
setChatId(chatId as ID<Chat>);
loadChat(chatId as ID<Chat>);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
@@ -75,11 +85,9 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
};
const sendMessage = () => {
if (!loadedChat) return;
if (!chat) return;
if (message.trim()) {
loadedChat.push(
Message.create({ text: message }, { owner: loadedChat?._owner }),
);
chat.push(Message.create({ text: message }, { owner: chat._owner }));
setMessage("");
}
};
@@ -129,7 +137,7 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
return (
<View className="flex flex-col h-full">
{!loadedChat ? (
{!chat ? (
<View className="flex flex-col h-full items-center justify-center">
<TouchableOpacity
onPress={createChat}

View File

@@ -1,14 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all of your component files.
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -1,70 +1,5 @@
# chat-vue
## 0.0.30
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-browser@0.8.51
- jazz-vue@0.8.51
## 0.0.29
### Patch Changes
- jazz-browser@0.8.50
- jazz-tools@0.8.50
- jazz-vue@0.8.50
## 0.0.28
### Patch Changes
- jazz-browser@0.8.49
- jazz-tools@0.8.49
- jazz-vue@0.8.49
## 0.0.27
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-browser@0.8.48
- jazz-vue@0.8.48
## 0.0.26
### Patch Changes
- Updated dependencies [6f0bd7f]
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-browser@0.8.45
- jazz-tools@0.8.45
- jazz-vue@0.8.45
## 0.0.25
### Patch Changes
- jazz-browser@0.8.44
- jazz-tools@0.8.44
- jazz-vue@0.8.44
## 0.0.24
### Patch Changes
- Updated dependencies [ac216b9]
- jazz-browser@0.8.41
- jazz-tools@0.8.41
- jazz-vue@0.8.41
## 0.0.23
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.30",
"version": "0.0.23",
"private": true,
"type": "module",
"scripts": {
@@ -30,7 +30,7 @@
"eslint-plugin-vue": "^9.28.0",
"npm-run-all2": "^6.2.3",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"vite": "^5.4.10",
"vite-plugin-vue-devtools": "^7.4.6",

View File

@@ -1,77 +1,5 @@
# jazz-example-chat
## 0.0.125
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-browser-media-images@0.8.51
- jazz-react@0.8.51
## 0.0.124
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
- jazz-browser-media-images@0.8.50
## 0.0.123
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
- jazz-browser-media-images@0.8.49
## 0.0.122
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-browser-media-images@0.8.48
- jazz-react@0.8.48
## 0.0.121
### Patch Changes
- Updated dependencies [6f0bd7f]
- Updated dependencies [fca6a0b]
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- cojson@0.8.45
- jazz-tools@0.8.45
- jazz-react@0.8.45
- jazz-browser-media-images@0.8.45
## 0.0.120
### Patch Changes
- Updated dependencies [5d20c81]
- cojson@0.8.44
- jazz-react@0.8.44
- jazz-tools@0.8.44
- jazz-browser-media-images@0.8.44
## 0.0.119
### Patch Changes
- Updated dependencies [3252502]
- Updated dependencies [6370348]
- Updated dependencies [ac216b9]
- cojson@0.8.41
- jazz-react@0.8.41
- jazz-tools@0.8.41
- jazz-browser-media-images@0.8.41
## 0.0.118
### Patch Changes

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Jazz Chat Example</title>
</head>
<body class="h-full bg-white text-stone-700 dark:text-stone-400 dark:bg-stone-925">
<body class="h-full">
<div id="root" class="h-full"></div>
<script type="module" src="/src/app.tsx"></script>
</body>

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.125",
"version": "0.0.118",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,24 +13,37 @@
"test:ui": "playwright test --ui"
},
"dependencies": {
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"hash-slash": "workspace:*",
"jazz-browser-media-images": "workspace:*",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"cojson": "workspace:0.8.39",
"hash-slash": "workspace:0.2.1",
"jazz-browser-media-images": "workspace:0.8.40",
"jazz-react": "workspace:0.8.40",
"jazz-tools": "workspace:0.8.39",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0",
"react-use": "^17.4.0",
"tailwind-merge": "^1.14.0",
"tailwindcss-animate": "^1.0.7",
"uniqolor": "^1.1.0"
},
"devDependencies": {
"@playwright/test": "^1.46.1",
"@types/qrcode": "^1.5.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}

View File

@@ -1,3 +1,78 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;
--card-foreground: 20 14.3% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 20 14.3% 4.1%;
--primary: 24 9.8% 10%;
--primary-foreground: 60 9.1% 97.8%;
--secondary: 60 4.8% 95.9%;
--secondary-foreground: 24 9.8% 10%;
--muted: 60 4.8% 95.9%;
--muted-foreground: 25 5.3% 44.7%;
--accent: 60 4.8% 95.9%;
--accent-foreground: 24 9.8% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 20 5.9% 90%;
--input: 20 5.9% 90%;
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
}
.dark {
--background: 20 14.3% 4.1%;
--foreground: 60 9.1% 97.8%;
--card: 20 14.3% 4.1%;
--card-foreground: 60 9.1% 97.8%;
--popover: 20 14.3% 4.1%;
--popover-foreground: 60 9.1% 97.8%;
--primary: 60 9.1% 97.8%;
--primary-foreground: 24 9.8% 10%;
--secondary: 12 6.5% 15.1%;
--secondary-foreground: 60 9.1% 97.8%;
--muted: 12 6.5% 15.1%;
--muted-foreground: 24 5.4% 63.9%;
--accent: 12 6.5% 15.1%;
--accent-foreground: 60 9.1% 97.8%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 60 9.1% 97.8%;
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--ring: 24 5.7% 82.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
margin: 0;
padding: 0;
}
}

View File

@@ -1,4 +1,3 @@
import { ThemeProvider } from "@/themeProvider.tsx";
import { DemoAuthBasicUI, createJazzReactApp, useDemoAuth } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
@@ -26,11 +25,9 @@ function JazzAndAuth({ children }: { children: React.ReactNode }) {
}
createRoot(document.getElementById("root")!).render(
<ThemeProvider>
<StrictMode>
<JazzAndAuth>
<App />
</JazzAndAuth>
</StrictMode>
</ThemeProvider>,
<StrictMode>
<JazzAndAuth>
<App />
</JazzAndAuth>
</StrictMode>,
);

View File

@@ -1,72 +0,0 @@
import { createContext, useContext, useEffect, useState } from "react";
type ThemeProviderProps = {
children: React.ReactNode;
defaultTheme?: string;
storageKey?: string;
};
type ThemeProviderState = {
theme: string;
setTheme: (theme: string) => void;
};
const initialState = {
theme: "system",
setTheme: () => null,
};
const ThemeProviderContext = createContext<ThemeProviderState>(initialState);
export function ThemeProvider({
children,
defaultTheme = "system",
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) {
const [theme, setTheme] = useState(
() => localStorage.getItem(storageKey) || defaultTheme,
);
useEffect(() => {
const root = window.document.documentElement;
root.classList.remove("light", "dark");
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
root.classList.add(systemTheme);
return;
}
root.classList.add(theme);
}, [theme]);
const value = {
theme,
setTheme: (theme: string) => {
localStorage.setItem(storageKey, theme);
setTheme(theme);
},
};
return (
<ThemeProviderContext.Provider {...props} value={value}>
{children}
</ThemeProviderContext.Provider>
);
}
// eslint-disable-next-line react-refresh/only-export-components
export const useTheme = () => {
const context = useContext(ThemeProviderContext);
if (context === undefined)
throw new Error("useTheme must be used within a ThemeProvider");
return context;
};

View File

@@ -1,79 +1,80 @@
import type { Config } from "tailwindcss";
import plugin from "tailwindcss/plugin";
const colors = require("tailwindcss/colors");
const stonePalette = {
50: "oklch(0.988281 0.002 75)",
75: "oklch(0.980563 0.002 75)",
100: "oklch(0.964844 0.002 75)",
200: "oklch(0.917969 0.002 75)",
300: "oklch(0.853516 0.002 75)",
400: "oklch(0.789063 0.002 75)",
500: "oklch(0.726563 0.002 75)",
600: "oklch(0.613281 0.002 75)",
700: "oklch(0.523438 0.002 75)",
800: "oklch(0.412109 0.002 75)",
900: "oklch(0.302734 0.002 75)",
925: "oklch(0.220000 0.002 75)",
950: "oklch(0.193359 0.002 75)",
} as const;
const stonePaletteWithAlpha = { ...stonePalette };
Object.keys(stonePalette).forEach((key) => {
stonePaletteWithAlpha[key] = stonePaletteWithAlpha[key].replace(
")",
"/ <alpha-value>)",
);
});
import animate from "tailwindcss-animate";
const config: Config = {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
darkMode: ["class"],
content: [
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
stone: stonePaletteWithAlpha,
blue: {
...colors.indigo,
500: "#5870F1",
DEFAULT: "#3313F7",
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
container: {
center: true,
padding: {
DEFAULT: "0.75rem",
sm: "1rem",
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
screens: {
md: "500px",
lg: "500px",
xl: "500px",
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [
plugin(({ addBase }) =>
addBase({
":root": {
"--gcmp-border-color": stonePalette[200],
"--gcmp-invert-border-color": stonePalette[900],
},
"*": {
borderColor: "var(--gcmp-border-color)",
},
"@media (prefers-color-scheme: dark)": {
"*": {
borderColor: "var(--gcmp-invert-border-color)",
},
},
"*:focus": {
outline: "none",
},
}),
),
],
} as const;
plugins: [animate],
};
export default config;

View File

@@ -38,11 +38,14 @@ test("chat between two users", async ({ page }) => {
await chatPage.sendMessage(message2ByLuigi);
await chatPage.expectMessageRow(message2ByLuigi);
await chatPage.logout();
await loginPage.loginAs(mario);
// This breaks with (Error: Error reading from peer storage, handling msg)
// await chatPage.logout();
// await loginPage.loginAs(mario);
await page.goto(roomURL);
// await chatPage.expectLoaded();
await chatPage.expectMessageRow(message1ByMario);
await chatPage.expectMessageRow(message2ByLuigi);
// await page.goto(roomURL);
// await chatPage.expectMessageRow(message1ByMario);
// await chatPage.expectMessageRow(message2ByLuigi);
});

View File

@@ -25,7 +25,7 @@ export class LoginPage {
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
name: `Log in as "${value}"`,
})
.click();
}

View File

@@ -1,68 +1,5 @@
# minimal-auth-clerk
## 0.0.24
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react@0.8.51
- jazz-react-auth-clerk@0.8.51
## 0.0.23
### Patch Changes
- jazz-react@0.8.50
- jazz-react-auth-clerk@0.8.50
- jazz-tools@0.8.50
## 0.0.22
### Patch Changes
- jazz-react@0.8.49
- jazz-react-auth-clerk@0.8.49
- jazz-tools@0.8.49
## 0.0.21
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react@0.8.48
- jazz-react-auth-clerk@0.8.48
## 0.0.20
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45
- jazz-react-auth-clerk@0.8.45
## 0.0.19
### Patch Changes
- jazz-react@0.8.44
- jazz-react-auth-clerk@0.8.44
- jazz-tools@0.8.44
## 0.0.18
### Patch Changes
- jazz-react@0.8.41
- jazz-react-auth-clerk@0.8.41
- jazz-tools@0.8.41
## 0.0.17
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.24",
"version": "0.0.17",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,7 +13,7 @@
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:0.8.51",
"jazz-react-auth-clerk": "workspace:0.8.40",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"

View File

@@ -1,61 +1,5 @@
# file-share-svelte
## 0.0.10
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-svelte@0.8.51
## 0.0.9
### Patch Changes
- jazz-tools@0.8.50
- jazz-svelte@0.8.50
## 0.0.8
### Patch Changes
- jazz-tools@0.8.49
- jazz-svelte@0.8.49
## 0.0.7
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-svelte@0.8.48
## 0.0.6
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-svelte@0.8.45
## 0.0.5
### Patch Changes
- jazz-tools@0.8.44
- jazz-svelte@0.8.44
## 0.0.4
### Patch Changes
- jazz-tools@0.8.41
- jazz-svelte@0.8.41
## 0.0.3
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.10",
"version": "0.0.3",
"private": true,
"type": "module",
"scripts": {
@@ -32,7 +32,7 @@
"prettier-plugin-tailwindcss": "^0.6.5",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"typescript-eslint": "^8.0.0",
"vite": "^5.4.10"

View File

@@ -27,7 +27,9 @@ export class FileShareAccount extends Account {
/** The account migration is run on account creation and on every log-in.
* You can use it to set up the account root and any other initial CoValues you need.
*/
async migrate() {
async migrate(creationProps?: { name: string }) {
super.migrate(creationProps);
await this._refs.root?.load();
// Initialize root if it doesn't exist

View File

@@ -22,6 +22,3 @@ dist-ssr
*.njsproj
*.sln
*.sw?
/test-results/
/playwright-report/

View File

@@ -1,68 +1,5 @@
# form
## 0.0.20
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-browser-media-images@0.8.51
- jazz-react@0.8.51
## 0.0.19
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
- jazz-browser-media-images@0.8.50
## 0.0.18
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
- jazz-browser-media-images@0.8.49
## 0.0.17
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-browser-media-images@0.8.48
- jazz-react@0.8.48
## 0.0.16
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45
- jazz-browser-media-images@0.8.45
## 0.0.15
### Patch Changes
- jazz-react@0.8.44
- jazz-tools@0.8.44
- jazz-browser-media-images@0.8.44
## 0.0.14
### Patch Changes
- jazz-react@0.8.41
- jazz-tools@0.8.41
- jazz-browser-media-images@0.8.41
## 0.0.13
### Patch Changes

View File

@@ -15,8 +15,6 @@ which has the same structure as `BubbleTeaOrder`, but with all fields set to `op
When the user is ready to submit the order, we treat `DraftBubbleTeaOrder` as a "real order" by
converting it into a `BubbleTeaOrder`.
[See the full guide here.](https://jazz.tools/docs/react/design-patterns/form)
## Installing & running the example locally
(This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation))

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.0.20",
"version": "0.0.13",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,20 +16,19 @@
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-hook-form": "^7.41.5"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.46.1",
"@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"is-ci": "^3.0.1",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}

View File

@@ -1,46 +0,0 @@
import { defineConfig, devices } from "@playwright/test";
import isCI from "is-ci";
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:5173/",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
permissions: ["clipboard-read", "clipboard-write"],
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Run your local dev server before starting the tests */
webServer: [
{
command: "pnpm preview --port 5173",
url: "http://localhost:5173/",
reuseExistingServer: !isCI,
},
],
});

View File

@@ -12,11 +12,11 @@ import {
} from "./schema.ts";
export function CreateOrder() {
const { me } = useAccount({ root: { draft: {}, orders: [] } });
const { me } = useAccount({ profile: { draft: {}, orders: [] } });
const router = useIframeHashRouter();
const [errors, setErrors] = useState<string[]>([]);
if (!me?.root) return;
if (!me?.profile) return;
const onSave = (draft: DraftBubbleTeaOrder) => {
// validate if the draft is a valid order
@@ -27,14 +27,14 @@ export function CreateOrder() {
}
// turn the draft into a real order
me.root.orders.push(draft as BubbleTeaOrder);
me.profile.orders.push(draft as BubbleTeaOrder);
// reset the draft
me.root.draft = DraftBubbleTeaOrder.create(
me.profile.draft = DraftBubbleTeaOrder.create(
{
addOns: ListOfBubbleTeaAddOns.create([], me),
addOns: ListOfBubbleTeaAddOns.create([], { owner: me.profile._owner }),
},
me,
{ owner: me.profile._owner },
);
router.navigate("/");
@@ -50,7 +50,7 @@ export function CreateOrder() {
<Errors errors={errors} />
<CreateOrderForm id={me?.root?.draft.id} onSave={onSave} />
<CreateOrderForm id={me?.profile?.draft.id} onSave={onSave} />
</>
);
}

View File

@@ -2,10 +2,10 @@ import { useAccount } from "./main.tsx";
export function DraftIndicator() {
const { me } = useAccount({
root: { draft: {} },
profile: { draft: {} },
});
if (me?.root.draft?.hasChanges) {
if (me?.profile.draft?.hasChanges) {
return (
<div className="absolute -top-1 -right-1 bg-blue-500 border-2 border-white w-3 h-3 rounded-full dark:border-stone-925">
<span className="sr-only">You have a draft</span>

View File

@@ -4,7 +4,7 @@ import { useAccount } from "./main.tsx";
export function Orders() {
const { me } = useAccount({
root: { orders: [] },
profile: { orders: [] },
});
return (
@@ -22,9 +22,8 @@ export function Orders() {
<h1 className="text-lg pb-2 border-b mb-3">
<strong>Your orders 🧋</strong>
</h1>
{me?.root?.orders?.length ? (
me?.root?.orders.map((order) =>
{me?.profile?.orders?.length ? (
me?.profile?.orders.map((order) =>
order ? <OrderThumbnail key={order.id} order={order} /> : null,
)
) : (

View File

@@ -1,4 +1,4 @@
import { Account, CoList, CoMap, co } from "jazz-tools";
import { Account, CoList, CoMap, Profile, co } from "jazz-tools";
export const BubbleTeaAddOnTypes = [
"Pearl",
@@ -59,29 +59,28 @@ export class DraftBubbleTeaOrder extends CoMap {
export class ListOfBubbleTeaOrders extends CoList.Of(co.ref(BubbleTeaOrder)) {}
/** The root is an app-specific per-user private `CoMap`
/** The profile is an app-specific per-user public `CoMap`
* where you can store top-level objects for that user */
export class AccountRoot extends CoMap {
export class JazzProfile extends Profile {
draft = co.ref(DraftBubbleTeaOrder);
orders = co.ref(ListOfBubbleTeaOrders);
}
export class JazzAccount extends Account {
root = co.ref(AccountRoot);
profile = co.ref(JazzProfile)!;
migrate() {
const account = this;
migrate(this: JazzAccount, creationProps?: { name: string }) {
super.migrate(creationProps);
if (!this._refs.root) {
const orders = ListOfBubbleTeaOrders.create([], account);
const draft = DraftBubbleTeaOrder.create(
if (!this.profile._refs.orders) {
const owner = this.profile._owner;
this.profile.orders = ListOfBubbleTeaOrders.create([], { owner });
this.profile.draft = DraftBubbleTeaOrder.create(
{
addOns: ListOfBubbleTeaAddOns.create([], account),
addOns: ListOfBubbleTeaAddOns.create([], { owner }),
},
account,
{ owner },
);
this.root = AccountRoot.create({ draft, orders }, account);
}
}
}

View File

@@ -1,56 +0,0 @@
import { expect, test } from "@playwright/test";
import { LoginPage } from "./pages/LoginPage";
test("create and edit an order", async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.fillUsername("Alice");
await loginPage.signup();
// start an order
await page.getByRole("link", { name: "Add new order" }).click();
await page.getByLabel("Base tea").selectOption("Oolong");
// test draft indicator
await page.getByRole("link", { name: /Back to all orders/ }).click();
await expect(page.getByText("You have a draft")).toBeVisible();
// fill out the rest of order form
await page.getByRole("link", { name: "Add new order" }).click();
await page.getByLabel("Pearl").check();
await page.getByLabel("Taro").check();
await page.getByLabel("Delivery date").fill("2024-12-21");
await page.getByLabel("With milk?").check();
await page.getByLabel("Special instructions").fill("25% sugar");
await page.getByRole("button", { name: "Submit" }).click();
await page.waitForURL("/");
// the draft indicator should be gone because the order was submitted
await expect(page.getByText("You have a draft")).toHaveCount(0);
// check if order was created correctly
const firstOrder = page.getByRole("link", { name: "Oolong milk tea" });
await expect(firstOrder).toHaveText(/25% sugar/);
await expect(firstOrder).toHaveText(/12\/21\/2024/);
await expect(firstOrder).toHaveText(/with pearl, taro/);
// edit order
await firstOrder.click();
await page.getByLabel("Base tea").selectOption("Jasmine");
await page.getByLabel("Red bean").check();
await page.getByLabel("Brown sugar").check();
await page.getByLabel("Delivery date").fill("2024-12-25");
await page.getByLabel("With milk?").uncheck();
await page.getByLabel("Special instructions").fill("10% sugar");
await page.getByRole("link", { name: /Back to all orders/ }).click();
// check if order was edited correctly
const editedOrder = page.getByRole("link", { name: "Jasmine tea" });
await expect(editedOrder).toHaveText(/10% sugar/);
await expect(editedOrder).toHaveText(/12\/25\/2024/);
await expect(editedOrder).toHaveText(
/with pearl, taro, red bean, brown sugar/,
);
});

View File

@@ -1,40 +0,0 @@
import { Locator, Page, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly signupButton: Locator;
constructor(page: Page) {
this.page = page;
this.usernameInput = page.getByRole("textbox");
this.signupButton = page.getByRole("button", {
name: "Sign up",
});
}
async goto() {
this.page.goto("/");
}
async fillUsername(value: string) {
await this.usernameInput.clear();
await this.usernameInput.fill(value);
}
async loginAs(value: string) {
await this.page
.getByRole("button", {
name: value,
})
.click();
}
async signup() {
await this.signupButton.click();
}
async expectLoaded() {
await expect(this.signupButton).toBeVisible();
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"root":["./src/app.tsx","./src/createorder.tsx","./src/draftindicator.tsx","./src/editorder.tsx","./src/errors.tsx","./src/linktohome.tsx","./src/orderform.tsx","./src/orderthumbnail.tsx","./src/orders.tsx","./src/main.tsx","./src/schema.ts","./src/vite-env.d.ts"],"version":"5.6.3"}

View File

@@ -1,2 +0,0 @@
declare const _default: import("vite").UserConfig;
export default _default;

View File

@@ -1,6 +0,0 @@
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});

View File

@@ -1,68 +1,5 @@
# image-upload
## 0.0.22
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-browser-media-images@0.8.51
- jazz-react@0.8.51
## 0.0.21
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
- jazz-browser-media-images@0.8.50
## 0.0.20
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
- jazz-browser-media-images@0.8.49
## 0.0.19
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-browser-media-images@0.8.48
- jazz-react@0.8.48
## 0.0.18
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45
- jazz-browser-media-images@0.8.45
## 0.0.17
### Patch Changes
- jazz-react@0.8.44
- jazz-tools@0.8.44
- jazz-browser-media-images@0.8.44
## 0.0.16
### Patch Changes
- jazz-react@0.8.41
- jazz-tools@0.8.41
- jazz-browser-media-images@0.8.41
## 0.0.15
### Patch Changes

View File

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

View File

@@ -10,5 +10,7 @@ export class JazzAccount extends Account {
/** The account migration is run on account creation and on every log-in.
* You can use it to set up the account root and any other initial CoValues you need.
*/
migrate(this: JazzAccount) {}
migrate(this: JazzAccount, creationProps?: { name: string }) {
super.migrate(creationProps);
}
}

View File

@@ -1,57 +1,5 @@
# jazz-example-inspector
## 0.0.92
### Patch Changes
- Updated dependencies [43378ef]
- cojson@0.8.50
- cojson-transport-ws@0.8.50
## 0.0.91
### Patch Changes
- Updated dependencies [25dfd90]
- cojson@0.8.49
- cojson-transport-ws@0.8.49
## 0.0.90
### Patch Changes
- Updated dependencies [10ea733]
- cojson@0.8.48
- cojson-transport-ws@0.8.48
## 0.0.89
### Patch Changes
- Updated dependencies [6f0bd7f]
- Updated dependencies [fca6a0b]
- Updated dependencies [88d7d9a]
- cojson@0.8.45
- cojson-transport-ws@0.8.45
## 0.0.88
### Patch Changes
- Updated dependencies [5d20c81]
- cojson@0.8.44
- cojson-transport-ws@0.8.44
## 0.0.87
### Patch Changes
- Updated dependencies [3252502]
- Updated dependencies [6370348]
- Updated dependencies [ac216b9]
- cojson@0.8.41
- cojson-transport-ws@0.8.41
## 0.0.86
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector",
"private": true,
"version": "0.0.92",
"version": "0.0.86",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,8 +16,8 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cojson": "workspace:0.8.50",
"cojson-transport-ws": "workspace:0.8.50",
"cojson": "workspace:0.8.39",
"cojson-transport-ws": "workspace:0.8.39",
"hash-slash": "workspace:0.2.1",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
@@ -37,7 +37,7 @@
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}

View File

@@ -1,61 +1,5 @@
# jazz-example-musicplayer
## 0.0.45
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react@0.8.51
## 0.0.44
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
## 0.0.43
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
## 0.0.42
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react@0.8.48
## 0.0.41
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45
## 0.0.40
### Patch Changes
- jazz-react@0.8.44
- jazz-tools@0.8.44
## 0.0.39
### Patch Changes
- jazz-react@0.8.41
- jazz-tools@0.8.41
## 0.0.38
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.45",
"version": "0.0.38",
"type": "module",
"scripts": {
"dev": "vite",
@@ -18,8 +18,8 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "workspace:0.8.51",
"jazz-tools": "workspace:0.8.51",
"jazz-react": "workspace:0.8.40",
"jazz-tools": "workspace:0.8.39",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
@@ -35,7 +35,7 @@
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}

View File

@@ -85,7 +85,9 @@ export class MusicaAccount extends Account {
* The account migration is run on account creation and on every log-in.
* You can use it to set up the account root and any other initial CoValues you need.
*/
migrate() {
async migrate(creationProps?: { name: string }) {
super.migrate(creationProps);
if (!this._refs.root) {
const ownership = { owner: this };

View File

@@ -29,23 +29,25 @@ export async function uploadMusicTracks(
for (const file of files) {
// The ownership object defines the user that owns the created coValues
// We are creating a group for each CoValue in order to be able to share them via Playlist
const group = Group.create(account);
const ownership = {
owner: Group.create({ owner: account }),
};
const data = await getAudioFileData(file);
// We transform the file blob into a FileStream
// making it a collaborative value that is encrypted, easy
// to share across devices and users and available offline!
const fileStream = await FileStream.createFromBlob(file, group);
const fileStream = await FileStream.createFromBlob(file, ownership);
const musicTrack = MusicTrack.create(
{
file: fileStream,
duration: data.duration,
waveform: MusicTrackWaveform.create({ data: data.waveform }, group),
waveform: MusicTrackWaveform.create({ data: data.waveform }, ownership),
title: file.name,
},
group,
ownership,
);
// The newly created musicTrack can be associated to the
@@ -58,14 +60,16 @@ export async function createNewPlaylist(account: MusicaAccount) {
// Since playlists are meant to be shared we associate them
// to a group which will contain the keys required to get
// access to the "owned" values
const playlistGroup = Group.create(account);
const playlistGroup = Group.create({ owner: account });
const ownership = { owner: playlistGroup };
const playlist = Playlist.create(
{
title: "New Playlist",
tracks: ListOfTracks.create([], playlistGroup),
tracks: ListOfTracks.create([], ownership),
},
playlistGroup,
ownership,
);
// Again, we associate the new playlist to the
@@ -108,6 +112,7 @@ export async function addTrackToPlaylist(
*
* Doing this for backwards compatibility for when the Group inheritance wasn't possible
*/
const ownership = { owner: playlist._owner };
const blob = await FileStream.loadAsBlob(track._refs.file.id, account);
const waveform = await MusicTrackWaveform.load(
track._refs.waveform.id,
@@ -119,16 +124,13 @@ export async function addTrackToPlaylist(
const trackClone = MusicTrack.create(
{
file: await FileStream.createFromBlob(blob, playlist._owner),
file: await FileStream.createFromBlob(blob, ownership),
duration: track.duration,
waveform: MusicTrackWaveform.create(
{ data: waveform.data },
playlist._owner,
),
waveform: MusicTrackWaveform.create({ data: waveform.data }, ownership),
title: track.title,
sourceTrack: track,
},
playlist._owner,
ownership,
);
playlist.tracks?.push(trackClone);

View File

@@ -1,68 +1,5 @@
# jazz-example-onboarding
## 0.0.26
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-browser-media-images@0.8.51
- jazz-react@0.8.51
## 0.0.25
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
- jazz-browser-media-images@0.8.50
## 0.0.24
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
- jazz-browser-media-images@0.8.49
## 0.0.23
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-browser-media-images@0.8.48
- jazz-react@0.8.48
## 0.0.22
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45
- jazz-browser-media-images@0.8.45
## 0.0.21
### Patch Changes
- jazz-react@0.8.44
- jazz-tools@0.8.44
- jazz-browser-media-images@0.8.44
## 0.0.20
### Patch Changes
- jazz-react@0.8.41
- jazz-tools@0.8.41
- jazz-browser-media-images@0.8.41
## 0.0.19
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-onboarding",
"private": true,
"version": "0.0.26",
"version": "0.0.19",
"type": "module",
"scripts": {
"dev": "vite",
@@ -29,7 +29,7 @@
"is-ci": "^3.0.1",
"jazz-run": "workspace:*",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"tailwindcss": "^3.4.9",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}

View File

@@ -66,7 +66,9 @@ export class HRProfile extends Profile {
export class HRAccount extends Account {
profile = co.ref(HRProfile)!;
migrate() {
migrate(this: HRAccount, creationProps?: { name: string }) {
super.migrate(creationProps);
if (!this.profile._refs.employees) {
this.profile.employees = EmployeeCoList.create([], {
owner: this.profile._owner,

View File

@@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,43 +0,0 @@
# organization
## 0.0.18
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react@0.8.51
## 0.0.17
### Patch Changes
- jazz-react@0.8.50
- jazz-tools@0.8.50
## 0.0.16
### Patch Changes
- jazz-react@0.8.49
- jazz-tools@0.8.49
## 0.0.15
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react@0.8.48
## 0.0.14
### Patch Changes
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-tools@0.8.45
- jazz-react@0.8.45

View File

@@ -1,40 +0,0 @@
# Organization example with Jazz and React
This is an example of how to share a set of data between users through a CoMap called Organization.
Different apps have different names for this concept, such as "teams" or "workspaces".
Refer to the [documentation](https://jazz.tools/docs/react/design-patterns/organization) for more information.
## Installing & running the example locally
(This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation))
Start by downloading the [jazz repository](https://github.com/garden-co/jazz):
```bash
npx degit gardencmp/jazz jazz
```
Go to the organization example directory:
```bash
cd jazz/examples/organization
```
Install and build dependencies:
```bash
pnpm i && npx turbo build
```
Start the dev server:
```bash
pnpm dev
```
## Questions / problems / feedback
If you have feedback, let us know on [Discord](https://discord.gg/utDMjHYg42) or open an issue or PR to fix something that seems wrong.
## Configuration: sync server
By default, the example app uses [Jazz Cloud](https://jazz.tools/cloud) (`wss://cloud.jazz.tools`) - so cross-device use, invites and collaboration should just work.
You can also run a local sync server by running `npx jazz-run sync` and adding the query param `?sync=ws://localhost:4200` to the URL of the example app (for example: `http://localhost:5173/?peer=ws://localhost:4200`), or by setting the `sync` parameter of the `<Jazz.Provider>` provider component in [./src/main.tsx](./src/main.tsx).

View File

@@ -1,12 +0,0 @@
<!doctype html>
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Jazz | Organization example</title>
</head>
<body class="h-full flex flex-col bg-gray-50 text-stone-700 dark:text-stone-400 dark:bg-stone-925">
<div id="root" class="align-self-center flex-1"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -1,35 +0,0 @@
{
"name": "organization",
"private": true,
"version": "0.0.18",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write"
},
"dependencies": {
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",
"postcss": "^8.4.27",
"tailwindcss": "^3.4.15",
"typescript": "~5.6.2",
"vite": "^5.4.10"
}
}

View File

@@ -1,6 +0,0 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -1,33 +0,0 @@
import { ID } from "jazz-tools";
import { useNavigate } from "react-router";
import { useAcceptInvite, useAccount } from "./main.tsx";
import { Organization } from "./schema.ts";
export function AcceptInvitePage() {
const navigate = useNavigate();
const { me } = useAccount({ root: { organizations: [] } });
const onAccept = (organizationId: ID<Organization>) => {
if (me?.root?.organizations) {
Organization.load(organizationId, me, []).then((organization) => {
if (organization) {
// avoid duplicates
const ids = me.root.organizations.map(
(organization) => organization?.id,
);
if (ids.includes(organizationId)) return;
me.root.organizations.push(organization);
navigate("/organizations/" + organizationId);
}
});
}
};
useAcceptInvite({
invitedObjectSchema: Organization,
onAccept,
});
return <p>Accepting invite...</p>;
}

View File

@@ -1,46 +0,0 @@
import { Layout } from "./Layout.tsx";
import { CreateOrganization } from "./components/CreateOrganization.tsx";
import { Heading } from "./components/Heading.tsx";
import { useAccount } from "./main.tsx";
export function HomePage() {
const { me } = useAccount({
root: { organizations: [{}] },
});
if (!me?.root.organizations) return;
return (
<Layout>
<Heading text="Organizations example app" />
<div className="rounded-lg border shadow-sm bg-white dark:bg-stone-925">
<div className="border-b px-4 py-5 sm:px-6">
<h2>Organizations</h2>
</div>
<div className="divide-y">
{me.root.organizations.length > 0 ? (
me.root.organizations.map((project) =>
project ? (
<a
key={project.id}
className="px-4 py-5 sm:px-6 font-medium block"
href={`/#/organizations/${project.id}`}
>
<strong>{project.name}</strong>
</a>
) : null,
)
) : (
<p className="col-span-full text-center px-4 py-8 sm:px-6">
You have no organizations yet.
</p>
)}
<div className="p-4 sm:p-6">
<CreateOrganization />
</div>
</div>
</div>
</Layout>
);
}

View File

@@ -1,39 +0,0 @@
import { UserIcon } from "lucide-react";
import { useAccount } from "./main.tsx";
export function Layout({ children }: { children: React.ReactNode }) {
const { me, logOut } = useAccount({
root: { draftOrganization: {} },
});
return (
<>
<header className="bg-white shadow-sm mb-12 dark:bg-stone-925 dark:border-b">
<div className="w-full max-w-4xl mx-auto px-4 py-3 flex gap-4 items-center">
<a href="/#">Home</a>
<span className="ml-auto flex items-center gap-2">
<span className="bg-stone-500 pt-1 size-6 flex items-center justify-center rounded-full">
<UserIcon size={20} className="stroke-white" />
</span>
{me?.profile?.name}
</span>
<button
className="bg-stone-100 py-1.5 px-3 text-sm rounded-md dark:bg-stone-900 dark:text-white"
onClick={() => {
window.location.href = "/";
logOut();
}}
>
Log out
</button>
</div>
</header>
<main className="px-4 py-3 max-w-4xl mx-auto flex flex-col gap-8">
{children}
</main>
</>
);
}

View File

@@ -1,72 +0,0 @@
import { ID } from "jazz-tools";
import { useParams } from "react-router";
import { Layout } from "./Layout.tsx";
import { CreateProject } from "./components/CreateProject.tsx";
import { Heading } from "./components/Heading.tsx";
import { InviteLink } from "./components/InviteLink.tsx";
import { OrganizationMembers } from "./components/OrganizationMembers.tsx";
import { useCoState } from "./main.tsx";
import { Organization } from "./schema.ts";
export function OrganizationPage() {
const paramOrganizationId = useParams<{ organizationId: ID<Organization> }>()
.organizationId;
const organization = useCoState(Organization, paramOrganizationId, {
projects: [],
});
if (!organization) return <p>Loading organization...</p>;
return (
<Layout>
<div className="grid gap-8">
<Heading text={`Welcome to ${organization.name} organization!`} />
<div className="rounded-lg border shadow-sm bg-white dark:bg-stone-925">
<div className="border-b px-4 py-5 sm:px-6">
<div className="flex justify-between items-center">
<h2>Members</h2>
{organization._owner?.myRole() === "admin" && (
<InviteLink organization={organization} />
)}
</div>
</div>
<div className="divide-y">
<OrganizationMembers organization={organization} />
</div>
</div>
<div className="rounded-lg border shadow-sm bg-white dark:bg-stone-925">
<div className="border-b px-4 py-5 sm:px-6">
<h2>Projects</h2>
</div>
<div className="divide-y">
{organization.projects.length > 0 ? (
organization.projects.map((project) =>
project ? (
<strong
key={project.id}
className="px-4 py-5 sm:px-6 font-medium block"
>
{project.name}
</strong>
) : null,
)
) : (
<p className="col-span-full text-center px-4 py-8 sm:px-6">
You have no projects yet.
</p>
)}
<div className="p-4 sm:p-6">
<CreateProject organization={organization} />
</div>
</div>
</div>
<div></div>
</div>
</Layout>
);
}

View File

@@ -1,68 +0,0 @@
import { Group, ID } from "jazz-tools";
import { useState } from "react";
import { useNavigate } from "react-router";
import { useAccount, useCoState } from "../main.tsx";
import { DraftOrganization, ListOfProjects, Organization } from "../schema.ts";
import { Errors } from "./Errors.tsx";
import { OrganizationForm } from "./OrganizationForm.tsx";
export function CreateOrganization() {
const { me } = useAccount({
root: { draftOrganization: {}, organizations: [] },
});
const [errors, setErrors] = useState<string[]>([]);
const navigate = useNavigate();
if (!me?.root?.organizations) return;
const onSave = (draft: DraftOrganization) => {
// validate if the draft is a valid organization
const validation = draft.validate();
setErrors(validation.errors);
if (validation.errors.length > 0) {
return;
}
const group = Group.create({ owner: me });
me.root.organizations.push(draft as Organization);
me.root.draftOrganization = DraftOrganization.create(
{
projects: ListOfProjects.create([], { owner: group }),
},
{ owner: group },
);
navigate(`/organizations/${draft.id}`);
};
return (
<>
{errors && <Errors errors={errors} />}
<CreateOrganizationForm
id={me?.root?.draftOrganization?.id}
onSave={onSave}
/>
</>
);
}
function CreateOrganizationForm({
id,
onSave,
}: {
id: ID<DraftOrganization>;
onSave: (draft: DraftOrganization) => void;
}) {
const draft = useCoState(DraftOrganization, id);
if (!draft) return;
const addOrganization = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
onSave(draft);
};
return <OrganizationForm organization={draft} onSave={addOrganization} />;
}

View File

@@ -1,46 +0,0 @@
import { useState } from "react";
import { Organization, Project } from "../schema.ts";
export function CreateProject({
organization,
}: {
organization: Organization;
}) {
const [name, setName] = useState<string>("");
const onSave = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (!organization?.projects) return;
if (name.length > 0) {
const project = Project.create({ name }, { owner: organization._owner });
organization.projects.push(project);
setName("");
}
};
return (
<form onSubmit={onSave} className="flex gap-3 items-center">
<label className="flex-1">
<span className="sr-only">Project name</span>
<input
type="text"
name="name"
id="name"
placeholder="Enter project name..."
value={name}
className="rounded-md shadow-sm dark:bg-transparent w-full"
onChange={(e) => setName(e.target.value)}
required
/>
</label>
<button
type="submit"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Add project
</button>
</form>
);
}

View File

@@ -1,13 +0,0 @@
export function Errors({ errors }: { errors: string[] }) {
if (errors.length === 0) return null;
return (
<div className="rounded-md bg-red-50 border border-red-50 p-4 text-sm text-red-600 dark:bg-transparent dark:border-red-500 dark:text-red-500">
<ul role="list" className="list-disc space-y-1 pl-5">
{errors.map((error, i) => (
<li key={i}>{error}</li>
))}
</ul>
</div>
);
}

View File

@@ -1,11 +0,0 @@
import { OrganizationSelector } from "./OrganizationSelector.tsx";
export function Heading({ text }: { text: string }) {
return (
<div className="flex justify-between">
<h1 className="text-3xl font-semibold">{text}</h1>
<OrganizationSelector />
</div>
);
}

View File

@@ -1,44 +0,0 @@
import { createInviteLink } from "jazz-react";
import { CheckIcon, CopyIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { Organization } from "../schema.ts";
export function InviteLink({ organization }: { organization: Organization }) {
const [inviteLink, setInviteLink] = useState<string>();
let [copyCount, setCopyCount] = useState(0);
let copied = copyCount > 0;
useEffect(() => {
if (organization) {
setInviteLink(createInviteLink(organization, "writer"));
}
}, [organization.id]);
useEffect(() => {
if (copyCount > 0) {
let timeout = setTimeout(() => setCopyCount(0), 1000);
return () => {
clearTimeout(timeout);
};
}
}, [copyCount]);
const copyUrl = () => {
if (inviteLink) {
navigator.clipboard.writeText(inviteLink).then(() => {
setCopyCount((count) => count + 1);
});
}
};
return (
<button
type="button"
className="inline-flex items-center gap-2 text-blue-500 dark:text-blue-400"
onClick={copyUrl}
>
{copied ? <CheckIcon size={16} /> : <CopyIcon size={16} />}
Copy invite link
</button>
);
}

View File

@@ -1,35 +0,0 @@
import { DraftOrganization, Organization } from "../schema.ts";
export function OrganizationForm({
organization,
onSave,
}: {
organization: Organization | DraftOrganization;
onSave?: (e: React.FormEvent<HTMLFormElement>) => void;
}) {
return (
<form onSubmit={onSave} className="flex gap-3 items-center">
<label className="flex-1">
<span className="sr-only">Organization name</span>
<input
type="text"
name="name"
id="name"
value={organization.name}
placeholder="Enter organization name..."
className="rounded-md shadow-sm dark:bg-transparent w-full"
onChange={(e) => (organization.name = e.target.value)}
required
/>
</label>
{onSave && (
<button
type="submit"
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
>
Submit
</button>
)}
</form>
);
}

View File

@@ -1,35 +0,0 @@
import { Account, Group, ID } from "jazz-tools";
import { useCoState } from "../main.tsx";
import { Organization } from "../schema.ts";
export function OrganizationMembers({
organization,
}: { organization: Organization }) {
const group = organization._owner.castAs(Group);
return (
<>
{group.members.map((member) => (
<Member
key={member.id}
accountId={member.id as ID<Account>}
role={member.role}
/>
))}
</>
);
}
function Member({
accountId,
role,
}: { accountId: ID<Account>; role?: string }) {
const account = useCoState(Account, accountId, { profile: {} });
if (!account?.profile) return;
return (
<div className="px-4 py-5 sm:px-6">
<strong className="font-medium">{account.profile.name}</strong> ({role})
</div>
);
}

View File

@@ -1,62 +0,0 @@
import { ID } from "jazz-tools";
import { UsersIcon } from "lucide-react";
import { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router";
import { useAccount } from "../main.tsx";
import { Organization } from "../schema.ts";
export function OrganizationSelector({ className }: { className?: string }) {
const { me } = useAccount({
root: { organizations: [{}] },
});
const navigate = useNavigate();
const paramOrganizationId = useParams<{ organizationId: ID<Organization> }>()
.organizationId;
const [organizationId, setOrganizationId] = useState<string | undefined>();
useEffect(() => {
if (paramOrganizationId) {
setOrganizationId(paramOrganizationId);
}
}, [paramOrganizationId]);
const onSelectOrganization = (e: React.ChangeEvent<HTMLSelectElement>) => {
const { value } = e.target;
if (value === "add") {
navigate("/#");
return;
}
setOrganizationId(value);
navigate(`/organizations/${value}`);
};
return (
<div className={[className, "flex items-center gap-3"].join(" ")}>
<label htmlFor="organization" className="md:sr-only">
Organization
</label>
<UsersIcon size={32} strokeWidth={1.5} />
<select
id="organization"
value={organizationId}
onChange={onSelectOrganization}
className="rounded-md shadow-sm dark:bg-transparent w-full"
>
{me?.root.organizations.map((organization) => {
return (
<option key={organization.id} value={organization.id}>
{organization.name}
</option>
);
})}
<option value="add">+ Create new organization</option>
</select>
</div>
);
}

View File

@@ -1,21 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
strong,
h1,
h2,
h3 {
@apply font-semibold text-stone-900 dark:text-white;
}
[type="text"],
select {
border-color: var(--gcmp-border-color);
@media (prefers-color-scheme: dark) {
border-color: var(--gcmp-invert-border-color);
}
}
}

View File

@@ -1,60 +0,0 @@
import { DemoAuthBasicUI, createJazzReactApp, useDemoAuth } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { RouterProvider, createHashRouter } from "react-router-dom";
import { AcceptInvitePage } from "./AcceptInvitePage.tsx";
import { HomePage } from "./HomePage.tsx";
import { OrganizationPage } from "./OrganizationPage.tsx";
import { JazzAccount } from "./schema.ts";
const Jazz = createJazzReactApp({
AccountSchema: JazzAccount,
});
export const { useAccount, useCoState, useAcceptInvite } = Jazz;
function Router() {
const router = createHashRouter([
{
path: "/",
element: <HomePage />,
},
{
path: "/organizations/:organizationId",
element: <OrganizationPage />,
},
{
path: "/invite/*",
element: <AcceptInvitePage />,
},
]);
return <RouterProvider router={router}></RouterProvider>;
}
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, authState] = useDemoAuth();
return (
<>
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=organization-example@garden.co"
>
{children}
</Jazz.Provider>
{authState.state !== "signedIn" && (
<DemoAuthBasicUI appName="Organization" state={authState} />
)}
</>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzAndAuth>
<Router />
</JazzAndAuth>
</StrictMode>,
);

View File

@@ -1,80 +0,0 @@
import { Account, CoList, CoMap, Group, co } from "jazz-tools";
export class Project extends CoMap {
name = co.string;
}
export class ListOfProjects extends CoList.Of(co.ref(Project)) {}
export class Organization extends CoMap {
name = co.string;
projects = co.ref(ListOfProjects);
}
export class DraftOrganization extends CoMap {
name = co.optional.string;
projects = co.ref(ListOfProjects);
validate() {
const errors: string[] = [];
if (!this.name) {
errors.push("Please enter a name.");
}
return {
errors,
};
}
}
export class ListOfOrganizations extends CoList.Of(co.ref(Organization)) {}
export class JazzAccountRoot extends CoMap {
organizations = co.ref(ListOfOrganizations);
draftOrganization = co.ref(DraftOrganization);
}
export class JazzAccount extends Account {
root = co.ref(JazzAccountRoot);
async migrate() {
if (!this._refs.root) {
const draftOrganizationOwnership = {
owner: Group.create({ owner: this }),
};
const draftOrganization = DraftOrganization.create(
{
projects: ListOfProjects.create([], draftOrganizationOwnership),
},
draftOrganizationOwnership,
);
const initialOrganizationOwnership = {
owner: Group.create({ owner: this }),
};
const organizations = ListOfOrganizations.create(
[
Organization.create(
{
name: this.profile?.name
? `${this.profile.name}'s projects`
: "Your projects",
projects: ListOfProjects.create([], initialOrganizationOwnership),
},
initialOrganizationOwnership,
),
],
{ owner: this },
);
this.root = JazzAccountRoot.create(
{
draftOrganization,
organizations,
},
{ owner: this },
);
}
}
}

View File

@@ -1 +0,0 @@
/// <reference types="vite/client" />

View File

@@ -1,75 +0,0 @@
import formsPlugin from "@tailwindcss/forms";
import type { Config } from "tailwindcss";
import plugin from "tailwindcss/plugin";
const stonePalette = {
50: "oklch(0.988281 0.002 75)",
75: "oklch(0.980563 0.002 75)",
100: "oklch(0.964844 0.002 75)",
200: "oklch(0.917969 0.002 75)",
300: "oklch(0.853516 0.002 75)",
400: "oklch(0.789063 0.002 75)",
500: "oklch(0.726563 0.002 75)",
600: "oklch(0.613281 0.002 75)",
700: "oklch(0.523438 0.002 75)",
800: "oklch(0.412109 0.002 75)",
900: "oklch(0.302734 0.002 75)",
925: "oklch(0.220000 0.002 75)",
950: "oklch(0.193359 0.002 75)",
} as const;
const stonePaletteWithAlpha = { ...stonePalette };
Object.keys(stonePalette).forEach((key) => {
stonePaletteWithAlpha[key] = stonePaletteWithAlpha[key].replace(
")",
"/ <alpha-value>)",
);
});
const config: Config = {
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
theme: {
extend: {
colors: {
stone: stonePaletteWithAlpha,
},
container: {
center: true,
padding: {
DEFAULT: "0.75rem",
sm: "1rem",
},
screens: {
md: "500px",
lg: "800px",
xl: "1100px",
},
},
},
},
plugins: [
formsPlugin,
plugin(({ addBase }) =>
addBase({
":root": {
"--gcmp-border-color": stonePalette[200],
"--gcmp-invert-border-color": stonePalette[900],
},
"*": {
borderColor: "var(--gcmp-border-color)",
},
"@media (prefers-color-scheme: dark)": {
"*": {
borderColor: "var(--gcmp-invert-border-color)",
},
},
"*:focus": {
outline: "none",
},
}),
),
],
} as const;
export default config;

View File

@@ -1,24 +0,0 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

View File

@@ -1,29 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}

View File

@@ -1,10 +0,0 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"root":["./src/acceptinvitepage.tsx","./src/homepage.tsx","./src/layout.tsx","./src/organizationpage.tsx","./src/main.tsx","./src/schema.ts","./src/vite-env.d.ts","./src/components/createorganization.tsx","./src/components/createproject.tsx","./src/components/errors.tsx","./src/components/heading.tsx","./src/components/invitelink.tsx","./src/components/organizationform.tsx","./src/components/organizationmembers.tsx","./src/components/organizationselector.tsx"],"version":"5.6.3"}

View File

@@ -1,2 +0,0 @@
declare const _default: import("vite").UserConfig;
export default _default;

View File

@@ -1,6 +0,0 @@
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});

View File

@@ -1,7 +0,0 @@
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});

View File

@@ -1,47 +1,5 @@
# passkey-svelte
## 0.0.14
### Patch Changes
- jazz-svelte@0.8.51
## 0.0.13
### Patch Changes
- jazz-svelte@0.8.50
## 0.0.12
### Patch Changes
- jazz-svelte@0.8.49
## 0.0.11
### Patch Changes
- jazz-svelte@0.8.48
## 0.0.10
### Patch Changes
- jazz-svelte@0.8.45
## 0.0.9
### Patch Changes
- jazz-svelte@0.8.44
## 0.0.8
### Patch Changes
- jazz-svelte@0.8.41
## 0.0.7
### Patch Changes

View File

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

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