Compare commits

..

41 Commits

Author SHA1 Message Date
Anselm
6571a6fb31 update start command 2024-09-23 16:14:28 -07:00
Anselm
1139605a7d update build command 2024-09-23 16:14:06 -07:00
Anselm
f40c80394d Add router refresh 2024-09-23 16:08:22 -07:00
Anselm
2bfb42dd4a Everything mostly working 2024-09-23 15:58:37 -07:00
Anselm
3ebdaa55c7 changes in jazz-react 2024-09-23 15:38:21 -07:00
Anselm
50dbd46c6c move and implement more 2024-09-23 15:38:08 -07:00
Anselm
37fbe504e3 Merge branch 'main' into lotion 2024-09-23 14:48:09 -07:00
Anselm
dc43f9a6b0 SSR start 2024-09-23 14:48:04 -07:00
Anselm
61535c80e3 create doc 2024-09-23 14:35:18 -07:00
Anselm
f3232b5361 Fix lockfile 2024-09-23 14:20:14 -07:00
Anselm
2b8f5ed3ca Release 2024-09-23 14:17:35 -07:00
Anselm
fcf0baee2e Fix jazz-run 2024-09-23 14:16:54 -07:00
Anselm
285b7609d6 skeleton 2024-09-23 14:15:58 -07:00
Anselm Eickhoff
07183ffe5b Merge pull request #443 from gardencmp/trishalim-jazz-333
Spacing improvements on landing pages (home and mesh)
2024-09-23 13:46:05 -07:00
Trisha Lim
11c36460ac Allow horizontal scroll on tabs 2024-09-23 20:28:51 +01:00
Trisha Lim
e0d7b266e7 Spacing improvements on mesh landing page 2024-09-23 20:27:02 +01:00
Trisha Lim
3706360ffc Make borders on dark mode more subtle 2024-09-23 20:22:03 +01:00
Trisha Lim
3d7a20ca64 Spacing improvements on homepage 2024-09-23 20:20:09 +01:00
Anselm Eickhoff
381ecaaf96 Merge pull request #438 from gardencmp/trishalim-jazz-331
Fix scroll issue on chat example
2024-09-23 09:30:14 -07:00
Anselm Eickhoff
25435ba597 Merge pull request #434 from gardencmp/trishalim-jazz-323
Make package name on side bar clickable
2024-09-23 09:29:03 -07:00
Trisha Lim
c56fd81bff Switch auth button copy to sentence case 2024-09-23 16:54:22 +01:00
Trisha Lim
707bf332d0 Fix scroll issue on chat example 2024-09-23 16:51:57 +01:00
Anselm Eickhoff
40225635f1 Merge pull request #436 from gardencmp/trishalim-jazz-326
Fix text colors in dark mode
2024-09-23 07:36:03 -07:00
Trisha Lim
e4ff701488 Fix text colors in dark mode 2024-09-23 15:25:06 +01:00
Anselm Eickhoff
314cdee815 Merge pull request #435 from gardencmp/trishalim-jazz-326 2024-09-23 07:07:30 -07:00
Trisha Lim
fa549f49b7 Fix heading colors in dark mode 2024-09-23 14:14:54 +01:00
Trisha Lim
c38460afd2 Fix inconsistent container width 2024-09-23 13:48:06 +01:00
Trisha Lim
7657c8469e Fix heading structure in docs 2024-09-23 13:11:28 +01:00
Trisha Lim
97abe86d7e Run pnpm format 2024-09-23 13:05:44 +01:00
Trisha Lim
a339dfaeb0 Make package name on side bar clickable 2024-09-23 13:05:25 +01:00
Anselm Eickhoff
3710776d09 Merge pull request #433 from gardencmp/anselm-jazz-330
Clean up chat example
2024-09-22 18:06:42 -07:00
Anselm
dffc2ee2fe Mention lines of code again 2024-09-22 18:01:15 -07:00
Anselm
cd47928252 Fix issues 2024-09-22 17:53:11 -07:00
Anselm
4b84ede0b5 Use two spaces for the chat examples 2024-09-22 17:46:27 -07:00
Anselm
0de4d684d8 Fix chat-clerk app.tsx 2024-09-22 17:36:33 -07:00
Anselm
d78a5364f6 Rename dumb components file 2024-09-22 17:32:52 -07:00
Anselm
228dfa1799 Clean up chat example 2024-09-22 17:25:50 -07:00
Anselm
74a66eaa94 Fix lockfile 2024-09-22 14:31:10 -07:00
Anselm
96670db342 Only build examples, don't deploy them on nomad anymore 2024-09-22 14:29:55 -07:00
Anselm
e4655c3705 Fix example auth components 2024-09-22 14:23:44 -07:00
Anselm
5a5f767b3d Fix versions & lockfile 2024-09-22 14:15:15 -07:00
153 changed files with 2700 additions and 841 deletions

View File

@@ -1,106 +0,0 @@
name: Build and Deploy
on:
push:
branches: [ "main" ]
jobs:
build-examples:
runs-on: ubuntu-latest
strategy:
matrix:
example: ["chat", "pets", "todo", "inspector"]
# example: ["twit", "chat", "counter-js-auth0", "pets", "twit", "file-drop", "inspector"]
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: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: gardencmp
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pnpm Build
run: |
pnpm install
pnpm turbo build;
working-directory: ./examples/${{ matrix.example }}
- name: Docker Build & Push
uses: docker/build-push-action@v4
with:
context: ./examples/${{ matrix.example }}
push: true
tags: ghcr.io/gardencmp/${{github.event.repository.name}}-example-${{ matrix.example }}:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy-examples:
runs-on: ubuntu-latest
needs: build-examples
strategy:
matrix:
example: ["chat", "pets", "todo", "inspector"]
# example: ["twit", "chat", "counter-js-auth0", "pets", "twit", "file-drop", "inspector"]
steps:
- uses: actions/checkout@v3
with:
submodules: true
- uses: gacts/install-nomad@v1
- name: Tailscale
uses: tailscale/github-action@v1
with:
authkey: ${{ secrets.TAILSCALE_AUTHKEY }}
- name: Deploy on Nomad
run: |
if [ "${{github.ref_name}}" == "main" ]; then
export BRANCH_SUFFIX="";
export BRANCH_SUBDOMAIN="";
else
export BRANCH_SUFFIX=-${{github.head_ref || github.ref_name}};
export BRANCH_SUBDOMAIN=${{github.head_ref || github.ref_name}}.;
fi
export DOCKER_USER=gardencmp;
export DOCKER_PASSWORD=${{ secrets.DOCKER_PULL_PAT }};
export DOCKER_TAG=ghcr.io/gardencmp/${{github.event.repository.name}}-example-${{ matrix.example }}:${{github.head_ref || github.ref_name}}-${{github.sha}}-${{github.run_number}}-${{github.run_attempt}};
envsubst '${DOCKER_USER} ${DOCKER_PASSWORD} ${DOCKER_TAG} ${BRANCH_SUFFIX} ${BRANCH_SUBDOMAIN}' < job-template.nomad > job-instance.nomad;
cat job-instance.nomad;
NOMAD_ADDR=${{ secrets.NOMAD_ADDR }} nomad job run job-instance.nomad;
working-directory: ./examples/${{ matrix.example }}

58
.github/workflows/build-examples.yaml vendored Normal file
View File

@@ -0,0 +1,58 @@
name: Build Examples
on:
push:
branches: [ "main" ]
jobs:
build-examples:
runs-on: ubuntu-latest
strategy:
matrix:
example: [
"chat",
"chat-clerk",
"inspector",
"music-player",
"password-manager",
"pets",
"todo",
]
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: ./examples/${{ matrix.example }}

View File

@@ -0,0 +1,9 @@
# @jazz-e2e/binarycostream
## 0.0.82
### Patch Changes
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1

View File

@@ -1,7 +1,7 @@
{
"name": "@jazz-e2e/binarycostream",
"private": true,
"version": "0.0.81",
"version": "0.0.82",
"type": "module",
"scripts": {
"dev": "vite",
@@ -14,11 +14,11 @@
"*.{js,jsx,mdx,json}": "prettier --write"
},
"dependencies": {
"cojson": "workspace:0.7.35-guest-auth.5",
"cojson": "workspace:0.8.0",
"hash-slash": "workspace:0.2.0",
"is-ci": "^3.0.1",
"jazz-react": "workspace:0.7.35-guest-auth.6",
"jazz-tools": "workspace:0.7.35-guest-auth.6",
"jazz-react": "workspace:0.8.1",
"jazz-tools": "workspace:0.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},

View File

@@ -2,12 +2,12 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {},
}
};

View File

@@ -22,3 +22,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
sync-db/

View File

@@ -0,0 +1,10 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 80
}

View File

@@ -1,88 +1,184 @@
# jazz-example-chat
## 0.0.80
## 0.0.81
### Patch Changes
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1
- jazz-react-auth-clerk@0.8.1
## 0.0.82
### Patch Changes
- bcec3be: Implement Clerk auth method + example
- Updated dependencies [6a147c2]
- Updated dependencies [ad40b88]
- Updated dependencies [23369dc]
- Updated dependencies [c2b62a0]
- Updated dependencies [bcec3be]
- Updated dependencies [1a979b6]
- Updated dependencies [bcec3be]
- Updated dependencies [6ce2051]
- cojson@0.8.0
- jazz-tools@0.8.0
- jazz-react@0.8.0
- jazz-react-auth-clerk@0.8.0
## 0.0.80-guest-auth.6
## 0.0.82-guest-auth.6
### Patch Changes
- Updated dependencies
- jazz-react@0.7.35-guest-auth.6
- jazz-tools@0.7.35-guest-auth.6
- jazz-react-auth-clerk@0.7.35-guest-auth.6
## 0.0.80-guest-auth.5
## 0.0.82
### Patch Changes
- Updated dependencies [49a8b54]
- Updated dependencies [35bbcd9]
- Updated dependencies [6f80282]
- Updated dependencies [35bbcd9]
- Updated dependencies [cac2ec9]
- Updated dependencies [f350e90]
- jazz-tools@0.7.35
- cojson@0.7.35
- jazz-react@0.7.35
## 0.0.81
### Patch Changes
- Updated dependencies [5d91f9f]
- Updated dependencies [5094e6d]
- Updated dependencies [b09589b]
- Updated dependencies [2c3a40c]
- Updated dependencies [4e16575]
- Updated dependencies [ea882ab]
- cojson@0.7.34
- jazz-react@0.7.34
- jazz-tools@0.7.34
## 0.0.81-neverthrow.6
### Patch Changes
- Updated dependencies
- cojson@0.7.35-guest-auth.5
- jazz-react@0.7.35-guest-auth.5
- jazz-react-auth-clerk@0.7.35-guest-auth.5
- jazz-tools@0.7.35-guest-auth.5
- cojson@0.7.34-neverthrow.8
- jazz-react@0.7.34-neverthrow.8
- jazz-tools@0.7.34-neverthrow.8
## 0.0.80-guest-auth.4
## 0.0.81-neverthrow.5
### Patch Changes
- Updated dependencies
- jazz-react@0.7.35-guest-auth.4
- jazz-tools@0.7.35-guest-auth.4
- jazz-react-auth-clerk@0.7.35-guest-auth.4
- cojson@0.7.34-neverthrow.7
- jazz-react@0.7.34-neverthrow.7
- jazz-tools@0.7.34-neverthrow.7
## 0.0.80-guest-auth.3
## 0.0.81-neverthrow.4
### Patch Changes
- Updated dependencies
- jazz-react@0.7.35-guest-auth.3
- jazz-tools@0.7.35-guest-auth.3
- jazz-react-auth-clerk@0.7.33-guest-auth.3
- cojson@0.7.34-neverthrow.4
- jazz-react@0.7.34-neverthrow.4
- jazz-tools@0.7.34-neverthrow.4
## 0.0.80-unique.2
## 0.0.81-neverthrow.3
### Patch Changes
- Updated dependencies
- jazz-tools@0.7.35-unique.2
- cojson@0.7.35-unique.2
- jazz-react@0.7.35-unique.2
- jazz-react-auth-clerk@0.7.33-unique.2
- cojson@0.7.34-neverthrow.3
- jazz-react@0.7.34-neverthrow.3
- jazz-tools@0.7.34-neverthrow.3
## 0.0.80-new-auth.1
## 0.0.81-neverthrow.2
### Patch Changes
- jazz-react@0.7.34-neverthrow.2
## 0.0.81-neverthrow.1
### Patch Changes
- Updated dependencies
- jazz-react@0.7.35-new-auth.1
- jazz-react-auth-clerk@0.7.33-new-auth.1
- cojson@0.7.34-neverthrow.1
- jazz-react@0.7.34-neverthrow.1
- jazz-tools@0.7.34-neverthrow.1
## 0.0.80-new-auth.0
## 0.0.81-neverthrow.0
### Patch Changes
- Implement Clerk auth method + example
- Updated dependencies
- cojson@0.7.34-neverthrow.0
- jazz-react@0.7.34-neverthrow.0
- jazz-tools@0.7.34-neverthrow.0
## 0.0.80
### Patch Changes
- Updated dependencies [b297c93]
- Updated dependencies [3bf5127]
- Updated dependencies [a8b74ff]
- Updated dependencies [db53161]
- cojson@0.7.33
- jazz-react@0.7.33
- jazz-tools@0.7.33
## 0.0.80-hotfixes.5
### Patch Changes
- Updated dependencies
- jazz-react-auth-clerk@0.7.33-new-auth.0
- jazz-react@0.7.35-new-auth.0
- jazz-tools@0.7.35-new-auth.0
- cojson@0.7.33-hotfixes.5
- jazz-react@0.7.33-hotfixes.5
- jazz-tools@0.7.33-hotfixes.5
## 0.0.80-hotfixes.4
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.4
- jazz-react@0.7.33-hotfixes.4
- jazz-tools@0.7.33-hotfixes.4
## 0.0.80-hotfixes.3
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.3
- jazz-react@0.7.33-hotfixes.3
- jazz-tools@0.7.33-hotfixes.3
## 0.0.80-hotfixes.2
### Patch Changes
- jazz-react@0.7.33-hotfixes.2
## 0.0.80-hotfixes.1
### Patch Changes
- jazz-react@0.7.33-hotfixes.1
## 0.0.80-hotfixes.0
### Patch Changes
- Updated dependencies
- cojson@0.7.33-hotfixes.0
- jazz-react@0.7.33-hotfixes.0
- jazz-tools@0.7.33-hotfixes.0
## 0.0.79

View File

@@ -1,19 +1,20 @@
# Jazz Chat Example
# Jazz Chat Example (with Clerk auth)
Live version: https://example-chat.jazz.tools
<!-- Live version: [https://chat-clerk.jazz.tools](https://chat-clerk.jazz.tools) -->
## Installing & running the example locally
(this requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation))
Start by checking out `jazz`
```bash
git clone https://github.com/gardencmp/jazz.git
cd jazz/examples/chat
cd jazz/examples/chat-clerk
pnpm pack --pack-destination /tmp
mkdir -p ~/jazz-examples/chat # or any other directory
tar -xf /tmp/jazz-example-chat-* --strip-components 1 -C ~/jazz-examples/chat
cd ~/jazz-examples/chat
mkdir -p ~/jazz-examples/chat-clerk # or any other directory
tar -xf /tmp/jazz-example-chat-* --strip-components 1 -C ~/jazz-examples/chat-clerk
cd ~/jazz-examples/chat-clerk
```
This ensures that you have the example app without git history and independent of the Jazz multi-package monorepo.
@@ -34,9 +35,8 @@ pnpm dev
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 Global Mesh](https://jazz.tools/mesh) (`wss://sync.jazz.tools`) - so cross-device use, invites and collaboration should just work.
You can also run a local sync server by running `npx cojson-simple-sync` and adding the query param `?sync=ws://localhost:4200` to the URL of the example app (for example: `http://localhost:5173/?sync=ws://localhost:4200`), or by setting the `sync` parameter of the `<Jazz.Provider>` provider component in [./src/2_main.tsx](./src/2_main.tsx).
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/2_main.tsx](./src/2_main.tsx).

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat-clerk",
"private": true,
"version": "0.0.80",
"version": "0.0.81",
"type": "module",
"scripts": {
"dev": "vite",
@@ -23,9 +23,9 @@
"clsx": "^2.0.0",
"cojson": "workspace:0.8.0",
"hash-slash": "workspace:0.2.0",
"jazz-react": "workspace:0.8.0",
"jazz-react-auth-clerk": "workspace:0.8.0",
"jazz-tools": "workspace:0.8.0",
"jazz-react": "workspace:0.8.1",
"jazz-react-auth-clerk": "workspace:0.8.1",
"jazz-tools": "workspace:0.8.1",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",

View File

@@ -3,4 +3,4 @@ export default {
tailwindcss: {},
autoprefixer: {},
},
}
};

View File

@@ -1,85 +1,30 @@
import { CoMap, CoList, co, Group, ID } from "jazz-tools";
import { createJazzReactApp } from "jazz-react";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
import { createRoot } from "react-dom/client";
import { Group, ID } from "jazz-tools";
import { useIframeHashRouter } from "hash-slash";
import { useAccount } from "./main.tsx";
import { Chat } from "./schema.ts";
import { ChatScreen } from "./chatScreen.tsx";
import { StrictMode } from "react";
import { AppContainer, TopBar } from "./ui.tsx";
import {
ClerkProvider,
SignInButton,
useAuth,
useClerk,
} from "@clerk/clerk-react";
export function App() {
const { me, logOut } = useAccount();
export class Message extends CoMap {
text = co.string;
const createChat = () => {
if (!me) return;
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
location.hash = "/chat/" + chat.id;
};
return (
<AppContainer>
<TopBar>
{me?.profile?.name} · <button onClick={logOut}>Log out</button>
</TopBar>
{useIframeHashRouter().route({
"/": () => createChat() as never,
"/chat/:id": id => <ChatScreen chatID={id as ID<Chat>} />,
})}
</AppContainer>
);
}
export class Chat extends CoList.Of(co.ref(Message)) {}
const Jazz = createJazzReactApp();
export const { useAccount, useCoState } = Jazz;
function AuthAndJazz({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return (
<>
{state.errors.map((error) => (
<div key={error}>{error}</div>
))}
{auth ? (
<Jazz.Provider
auth={auth}
peer="wss://mesh.jazz.tools/?key=chat-example-jazz-clerk@gcmp.io"
>
{children}
</Jazz.Provider>
) : (
<SignInButton />
)}
</>
);
}
function App() {
const { signOut } = useAuth();
const { me } = useAccount();
const createChat = () => {
if (!me) return;
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
location.hash = "/chat/" + chat.id;
};
return (
<div className="flex flex-col items-center justify-between w-screen h-screen p-2 dark:bg-black dark:text-white">
<div className="rounded mb-5 px-2 py-1 text-sm self-end">
{me?.profile?.name} ·{" "}
<button onClick={() => signOut()}>Log Out</button>
</div>
{useIframeHashRouter().route({
"/": () => createChat() as never,
"/chat/:id": (id) => <ChatScreen chatID={id as ID<Chat>} />,
})}
</div>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ClerkProvider
publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}
afterSignOutUrl="/"
>
<AuthAndJazz>
<App />
</AuthAndJazz>
</ClerkProvider>
</StrictMode>
);

View File

@@ -1,42 +1,43 @@
import { ID } from 'jazz-tools';
import { Chat, Message, useCoState } from './app.tsx';
import { ID } from "jazz-tools";
import { Chat, Message } from "./schema.ts";
import { useCoState } from "./main.tsx";
import {
BubbleBody,
BubbleContainer,
BubbleInfo,
ChatContainer,
ChatInput,
EmptyChatMessage,
} from "./ui.tsx";
export function ChatScreen(props: { chatID: ID<Chat> }) {
const chat = useCoState(Chat, props.chatID, [{}]);
return chat ? <div className='w-full max-w-xl h-full flex flex-col items-stretch'>
{chat.length > 0
? chat.map((msg) => <ChatBubble msg={msg} key={msg.id} />)
: <div className='m-auto text-sm'>(Empty chat)</div>}
<ChatInput onSubmit={(text) => {
chat.push(
Message.create({ text }, { owner: chat._owner })
);
}} />
</div> : <div>Loading...</div>;
return chat ? (
<ChatContainer>
{chat.length > 0 ? (
chat.map(msg => <ChatBubble msg={msg} key={msg.id} />)
) : (
<EmptyChatMessage />
)}
<ChatInput
onSubmit={text => {
chat.push(Message.create({ text }, { owner: chat._owner }));
}}
/>
</ChatContainer>
) : (
<div>Loading...</div>
);
}
function ChatBubble(props: { msg: Message }) {
const lastEdit = props.msg._edits.text;
const align = lastEdit.by?.isMe ? 'items-end' : 'items-start';
return <div className={`${align} flex flex-col`}>
<div className='rounded-xl bg-stone-100 dark:bg-stone-700 dark:text-white py-2 px-4 mt-2 min-w-[5rem]'>
{ props.msg.text }
</div>
<div className='text-xs text-neutral-500 ml-2'>
{ lastEdit.by?.profile?.name }{' '}
{ lastEdit.madeAt?.toLocaleTimeString() }
</div>
</div>;
}
function ChatInput(props: { onSubmit: (text: string) => void }) {
return <input className='rounded p-2 border mt-auto dark:bg-black dark:text-white border-stone-300 dark:border-stone-700'
placeholder='Type a message and press Enter'
onKeyDown={({ key, currentTarget: input }) => {
if (key !== 'Enter' || !input.value) return;
props.onSubmit(input.value);
input.value = '';
}} />;
return (
<BubbleContainer fromMe={lastEdit.by?.isMe}>
<BubbleBody>{props.msg.text}</BubbleBody>
<BubbleInfo by={lastEdit.by?.profile?.name} madeAt={lastEdit.madeAt} />
</BubbleContainer>
);
}

View File

@@ -75,4 +75,4 @@
margin: 0;
padding: 0;
}
}
}

View File

@@ -0,0 +1,46 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { createJazzReactApp } from "jazz-react";
import { App } from "./app.tsx";
import { ClerkProvider, SignInButton, useClerk } from "@clerk/clerk-react";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
const Jazz = createJazzReactApp();
export const { useAccount, useCoState } = Jazz;
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
return (
<>
{state.errors.map(error => (
<div key={error}>{error}</div>
))}
{auth ? (
<Jazz.Provider
auth={auth}
peer="wss://mesh.jazz.tools/?key=chat-example-jazz-clerk@gcmp.io"
>
{children}
</Jazz.Provider>
) : (
<SignInButton />
)}
</>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ClerkProvider
publishableKey={import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}
afterSignOutUrl="/"
>
<JazzAndAuth>
<App />
</JazzAndAuth>
</ClerkProvider>
</StrictMode>
);

View File

@@ -0,0 +1,7 @@
import { CoMap, CoList, co } from "jazz-tools";
export class Message extends CoMap {
text = co.string;
}
export class Chat extends CoList.Of(co.ref(Message)) {}

View File

@@ -0,0 +1,63 @@
export function AppContainer(props: { children: React.ReactNode }) {
return (
<div className="flex flex-col items-center justify-between w-screen h-screen p-2 dark:bg-black dark:text-white">
{props.children}
</div>
);
}
export function TopBar(props: { children: React.ReactNode }) {
return (
<div className="mb-5 px-2 py-1 text-sm self-end">{props.children}</div>
);
}
export function ChatContainer(props: { children: React.ReactNode }) {
return (
<div className="w-full max-w-xl h-full flex flex-col items-stretch">
{props.children}
</div>
);
}
export function EmptyChatMessage() {
return <div className="m-auto text-sm">(Empty chat)</div>;
}
export function BubbleContainer(props: {
children: React.ReactNode;
fromMe: boolean | undefined;
}) {
const align = props.fromMe ? "items-end" : "items-start";
return <div className={`${align} flex flex-col`}>{props.children}</div>;
}
export function BubbleBody(props: { children: React.ReactNode }) {
return (
<div className="rounded-xl bg-stone-100 dark:bg-stone-700 dark:text-white py-2 px-4 mt-2 min-w-[5rem]">
{props.children}
</div>
);
}
export function BubbleInfo(props: { by: string | undefined; madeAt: Date }) {
return (
<div className="text-xs text-neutral-500 ml-2">
{props.by} {props.madeAt.toLocaleTimeString()}
</div>
);
}
export function ChatInput(props: { onSubmit: (text: string) => void }) {
return (
<input
className="rounded p-2 border mt-auto dark:bg-black dark:text-white border-stone-300 dark:border-stone-700"
placeholder="Type a message and press Enter"
onKeyDown={({ key, currentTarget: input }) => {
if (key !== "Enter" || !input.value) return;
props.onSubmit(input.value);
input.value = "";
}}
/>
);
}

View File

@@ -1,11 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
],
theme: {
container: {
center: true,
@@ -72,4 +72,4 @@ module.exports = {
},
},
plugins: [require("tailwindcss-animate")],
}
};

View File

@@ -1,5 +1,5 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
// https://vitejs.dev/config/
@@ -11,6 +11,6 @@ export default defineConfig({
},
},
build: {
minify: false
}
})
minify: false,
},
});

View File

@@ -2,12 +2,12 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {},
}
};

10
examples/chat/.prettierrc Normal file
View File

@@ -0,0 +1,10 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 80
}

View File

@@ -1,5 +1,13 @@
# jazz-example-chat
## 0.0.83
### Patch Changes
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1
## 0.0.82
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.82",
"version": "0.0.83",
"type": "module",
"scripts": {
"dev": "vite",
@@ -22,8 +22,8 @@
"clsx": "^2.0.0",
"cojson": "workspace:0.8.0",
"hash-slash": "workspace:0.2.0",
"jazz-react": "workspace:0.8.0",
"jazz-tools": "workspace:0.8.0",
"jazz-react": "workspace:0.8.1",
"jazz-tools": "workspace:0.8.1",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",

View File

@@ -3,4 +3,4 @@ export default {
tailwindcss: {},
autoprefixer: {},
},
}
};

View File

@@ -1,65 +1,30 @@
import { CoMap, CoList, co, Group, ID } from "jazz-tools";
import { createJazzReactApp, DemoAuthBasicUI, useDemoAuth } from "jazz-react";
import { createRoot } from "react-dom/client";
import { Group, ID } from "jazz-tools";
import { useIframeHashRouter } from "hash-slash";
import { useAccount } from "./main.tsx";
import { Chat } from "./schema.ts";
import { ChatScreen } from "./chatScreen.tsx";
import { StrictMode } from "react";
import { AppContainer, TopBar } from "./ui.tsx";
export class Message extends CoMap {
text = co.string;
export function App() {
const { me, logOut } = useAccount();
const createChat = () => {
if (!me) return;
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
location.hash = "/chat/" + chat.id;
};
return (
<AppContainer>
<TopBar>
{me?.profile?.name} · <button onClick={logOut}>Log out</button>
</TopBar>
{useIframeHashRouter().route({
"/": () => createChat() as never,
"/chat/:id": id => <ChatScreen chatID={id as ID<Chat>} />,
})}
</AppContainer>
);
}
export class Chat extends CoList.Of(co.ref(Message)) {}
const Jazz = createJazzReactApp();
export const { useAccount, useCoState } = Jazz;
function App() {
const { me, logOut } = useAccount();
const createChat = () => {
if (!me) return;
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
location.hash = "/chat/" + chat.id;
};
return (
<div className="flex flex-col items-center justify-between w-screen h-screen p-2 dark:bg-black dark:text-white">
<div className="rounded mb-5 px-2 py-1 text-sm self-end">
{me?.profile?.name} ·{" "}
<button onClick={logOut}>Log Out</button>
</div>
{useIframeHashRouter().route({
"/": () => createChat() as never,
"/chat/:id": (id) => <ChatScreen chatID={id as ID<Chat>} />,
})}
</div>
);
}
function AuthAndJazz({ children }: { children: React.ReactNode }) {
const [auth, state] = useDemoAuth();
return (
<Jazz.Provider
auth={auth}
peer="wss://mesh.jazz.tools/?key=chat-example-jazz@gcmp.io"
>
{state.state === "signedIn" ? (
children
) : (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
)}
</Jazz.Provider>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<AuthAndJazz>
<App />
</AuthAndJazz>
</StrictMode>
);

View File

@@ -1,42 +1,43 @@
import { ID } from 'jazz-tools';
import { Chat, Message, useCoState } from './app.tsx';
import { ID } from "jazz-tools";
import { Chat, Message } from "./schema.ts";
import { useCoState } from "./main.tsx";
import {
BubbleBody,
BubbleContainer,
BubbleInfo,
ChatContainer,
ChatInput,
EmptyChatMessage,
} from "./ui.tsx";
export function ChatScreen(props: { chatID: ID<Chat> }) {
const chat = useCoState(Chat, props.chatID, [{}]);
return chat ? <div className='w-full max-w-xl h-full flex flex-col items-stretch'>
{chat.length > 0
? chat.map((msg) => <ChatBubble msg={msg} key={msg.id} />)
: <div className='m-auto text-sm'>(Empty chat)</div>}
<ChatInput onSubmit={(text) => {
chat.push(
Message.create({ text }, { owner: chat._owner })
);
}} />
</div> : <div>Loading...</div>;
return chat ? (
<ChatContainer>
{chat.length > 0 ? (
chat.map(msg => <ChatBubble msg={msg} key={msg.id} />)
) : (
<EmptyChatMessage />
)}
<ChatInput
onSubmit={text => {
chat.push(Message.create({ text }, { owner: chat._owner }));
}}
/>
</ChatContainer>
) : (
<div>Loading...</div>
);
}
function ChatBubble(props: { msg: Message }) {
const lastEdit = props.msg._edits.text;
const align = lastEdit.by?.isMe ? 'items-end' : 'items-start';
return <div className={`${align} flex flex-col`}>
<div className='rounded-xl bg-stone-100 dark:bg-stone-700 dark:text-white py-2 px-4 mt-2 min-w-[5rem]'>
{ props.msg.text }
</div>
<div className='text-xs text-neutral-500 ml-2'>
{ lastEdit.by?.profile?.name }{' '}
{ lastEdit.madeAt?.toLocaleTimeString() }
</div>
</div>;
}
function ChatInput(props: { onSubmit: (text: string) => void }) {
return <input className='rounded p-2 border mt-auto dark:bg-black dark:text-white border-stone-300 dark:border-stone-700'
placeholder='Type a message and press Enter'
onKeyDown={({ key, currentTarget: input }) => {
if (key !== 'Enter' || !input.value) return;
props.onSubmit(input.value);
input.value = '';
}} />;
return (
<BubbleContainer fromMe={lastEdit.by?.isMe}>
<BubbleBody>{props.msg.text}</BubbleBody>
<BubbleInfo by={lastEdit.by?.profile?.name} madeAt={lastEdit.madeAt} />
</BubbleContainer>
);
}

View File

@@ -75,4 +75,4 @@
margin: 0;
padding: 0;
}
}
}

View File

@@ -0,0 +1,33 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { createJazzReactApp, DemoAuthBasicUI, useDemoAuth } from "jazz-react";
import { App } from "./app.tsx";
const Jazz = createJazzReactApp();
export const { useAccount, useCoState } = Jazz;
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, state] = useDemoAuth();
console.log(state, auth)
return (
<>
<Jazz.Provider
auth={auth}
peer="wss://mesh.jazz.tools/?key=chat-example-jazz@gcmp.io"
>
{children}
</Jazz.Provider>
{state.state !== "signedIn" && <DemoAuthBasicUI appName="Jazz Chat" state={state} />}
</>
);
}
createRoot(document.getElementById("root")!).render(
<StrictMode>
<JazzAndAuth>
<App />
</JazzAndAuth>
</StrictMode>
);

View File

@@ -0,0 +1,7 @@
import { CoMap, CoList, co } from "jazz-tools";
export class Message extends CoMap {
text = co.string;
}
export class Chat extends CoList.Of(co.ref(Message)) {}

63
examples/chat/src/ui.tsx Normal file
View File

@@ -0,0 +1,63 @@
export function AppContainer(props: { children: React.ReactNode }) {
return (
<div className="flex flex-col items-center justify-between w-screen h-screen p-2 dark:bg-black dark:text-white">
{props.children}
</div>
);
}
export function TopBar(props: { children: React.ReactNode }) {
return (
<div className="mb-5 px-2 py-1 text-sm self-end">{props.children}</div>
);
}
export function ChatContainer(props: { children: React.ReactNode }) {
return (
<div className="w-full max-w-xl h-full flex flex-col items-stretch">
{props.children}
</div>
);
}
export function EmptyChatMessage() {
return <div className="m-auto text-sm">(Empty chat)</div>;
}
export function BubbleContainer(props: {
children: React.ReactNode;
fromMe: boolean | undefined;
}) {
const align = props.fromMe ? "items-end" : "items-start";
return <div className={`${align} flex flex-col`}>{props.children}</div>;
}
export function BubbleBody(props: { children: React.ReactNode }) {
return (
<div className="rounded-xl bg-stone-100 dark:bg-stone-700 dark:text-white py-2 px-4 mt-2 min-w-[5rem]">
{props.children}
</div>
);
}
export function BubbleInfo(props: { by: string | undefined; madeAt: Date }) {
return (
<div className="text-xs text-neutral-500 ml-2">
{props.by} {props.madeAt.toLocaleTimeString()}
</div>
);
}
export function ChatInput(props: { onSubmit: (text: string) => void }) {
return (
<input
className="rounded p-2 border mt-auto dark:bg-black dark:text-white border-stone-300 dark:border-stone-700"
placeholder="Type a message and press Enter"
onKeyDown={({ key, currentTarget: input }) => {
if (key !== "Enter" || !input.value) return;
props.onSubmit(input.value);
input.value = "";
}}
/>
);
}

View File

@@ -1,11 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
"./pages/**/*.{ts,tsx}",
"./components/**/*.{ts,tsx}",
"./app/**/*.{ts,tsx}",
"./src/**/*.{ts,tsx}",
],
theme: {
container: {
center: true,
@@ -72,4 +72,4 @@ module.exports = {
},
},
plugins: [require("tailwindcss-animate")],
}
};

View File

@@ -1,5 +1,5 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
// https://vitejs.dev/config/
@@ -11,6 +11,6 @@ export default defineConfig({
},
},
build: {
minify: false
}
})
minify: false,
},
});

View File

@@ -1,5 +1,13 @@
# jazz-example-musicplayer
## 0.0.4
### Patch Changes
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1
## 0.0.3
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.3",
"version": "0.0.4",
"type": "module",
"scripts": {
"dev": "vite",
@@ -17,8 +17,8 @@
"dependencies": {
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"jazz-react": "workspace:0.8.0",
"jazz-tools": "workspace:0.8.0",
"jazz-react": "workspace:0.8.1",
"jazz-tools": "workspace:0.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router": "^6.16.0",

View File

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -96,20 +96,23 @@ function Main() {
);
}
function AuthAndJazz({ children }: { children: React.ReactNode }) {
function JazzAndAuth({ children }: { children: React.ReactNode }) {
const [auth, state] = useDemoAuth();
return (
<Jazz.Provider auth={auth} peer="wss://mesh.jazz.tools/?key=music-player-example-jazz@gcmp.io">
{state.state === "signedIn" ? children : <DemoAuthBasicUI appName="Jazz Music Player" state={state} />}
</Jazz.Provider>
<>
<Jazz.Provider auth={auth} peer="wss://mesh.jazz.tools/?key=music-player-example-jazz@gcmp.io">
{children}
</Jazz.Provider>
<DemoAuthBasicUI appName="Jazz Music Player" state={state} />
</>
);
}
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AuthAndJazz>
<JazzAndAuth>
<Main />
</AuthAndJazz>
</JazzAndAuth>
</React.StrictMode>,
);

View File

@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}

36
examples/next-ssr/.gitignore vendored Normal file
View File

@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -0,0 +1,10 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 80
}

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,41 @@
"use client";
import { useAccount } from "../jazz-client";
import { Doc } from "../schema";
import { useRouter } from "next/navigation";
export function NewDocButton() {
const { me } = useAccount();
const router = useRouter();
function createDoc() {
if (!me) return;
const document = Doc.create(
{
title: "Untitled",
text: "Lorem ipsum...",
tweet: "",
},
{ owner: me }
);
setTimeout(() => {
router.push(`/doc/${document.id}`);
router.refresh();
}, 200);
}
return (
<button
className={
(me ? "bg-blue-500" : "bg-gray-500") +
" text-white px-4 py-2 rounded-md"
}
onClick={createDoc}
disabled={!me}
>
Create new document
</button>
);
}

View File

@@ -0,0 +1,13 @@
import { NewDocButton } from "./newDocButton";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<h1 className="text-4xl font-bold">Lotion</h1>
<NewDocButton />
</main>
</div>
);
}

View File

@@ -0,0 +1,17 @@
"use client";
import { ID } from "jazz-tools";
import { useCoState } from "../../jazz-client";
import { Doc } from "../../schema";
import { RenderDoc } from "./renderDoc";
export function ClientDoc({ docId, ssrDoc }: { docId: ID<Doc>; ssrDoc: Doc }) {
const doc = useCoState(Doc, docId);
return (
<>
<RenderDoc doc={doc || ssrDoc} />
<div>{doc ? "client" : <span className="bg-red">ssr</span>}</div>
</>
);
}

View File

@@ -0,0 +1,45 @@
import { Doc } from "@/app/schema";
import { JazzSSRPromise } from "@/app/jazz-server";
import { ClientDoc } from "./clientDoc";
import { ID } from "jazz-tools";
export default async function DocPage({
params,
}: {
params: { docId: string };
}) {
const JazzSSR = await JazzSSRPromise;
console.log("Loaded ssrJazz");
const ssrDoc = await new Promise((resolve) => {
let latestDoc: Doc | undefined = undefined;
Doc.subscribe(params.docId as ID<Doc>, JazzSSR.worker, {}, (doc) => {
latestDoc = doc;
});
setTimeout(() => {
if (latestDoc) {
resolve(latestDoc);
}
}, 100);
});
console.log("Loaded ssrDoc", ssrDoc);
if (!ssrDoc) {
return <div>Doc not found</div>;
}
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-8 row-start-2 items-center sm:items-start">
<div>Doc {params.docId}</div>
<ClientDoc
docId={params.docId as ID<Doc>}
ssrDoc={{ ...ssrDoc } as Doc}
/>
</main>
</div>
);
}

View File

@@ -0,0 +1,33 @@
import { Doc } from "../../schema";
import { Tweet } from 'react-tweet'
export function RenderDoc({ doc }: { doc: Doc }) {
return (
<>
<input
type="text"
value={doc.title}
className="border rounded p-2 text-2xl font-bold"
onChange={(e) => {
doc.title = e.target.value;
}}
/>
<textarea
value={doc.text}
className="border rounded p-2 text-lg"
onChange={(e) => {
doc.text = e.target.value;
}}
/>
<input
type="text"
value={doc.tweet}
className="border rounded p-2 text-lg"
onChange={(e) => {
doc.tweet = e.target.value;
}}
/>
{doc.tweet && <Tweet id={doc.tweet} />}
</>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: #ffffff;
--foreground: #171717;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}

View File

@@ -0,0 +1,6 @@
import { ID, Account } from "jazz-tools";
export const hardcodedUserCredentials = {
accountID: "co_z9vEwRPyv91S1DjgK7YZrU3L2qQ" as ID<Account>,
secret: "sealerSecret_z2EYHmgJdUo4eDzYAQV8mz4PFTwnQrZTJCpBSiBiofEgT/signerSecret_z9k8kci8cskPBuRQmQUDKszEH6UJJCHvMzG9rx6Wxvpgh" as const
};

View File

@@ -0,0 +1,37 @@
"use client";
import { createJazzReactApp } from "jazz-react";
import {
Account,
fixedCredentialsAuth,
ID,
} from "jazz-tools";
const JazzClient = createJazzReactApp();
export const { useCoState, useAccount } = JazzClient;
export function JazzClientContext({
children,
credentials,
}: {
children: React.ReactNode;
credentials: {
accountID: ID<Account>;
secret: `sealerSecret_z${string}/signerSecret_z${string}`;
};
}) {
return (
<JazzClient.Provider
auth={{
async start(crypto) {
await new Promise((resolve) => setTimeout(resolve, 3000));
return fixedCredentialsAuth(credentials).start(crypto)
}
}}
peer="wss://mesh.jazz.tools/?key=you@example.com"
>
{children}
</JazzClient.Provider>
);
}

View File

@@ -0,0 +1,9 @@
import "next/server";
import { hardcodedUserCredentials } from "./hardcodedUserCredentials";
import { startWorker } from "jazz-nodejs";
export const JazzSSRPromise = startWorker({
accountID: hardcodedUserCredentials.accountID,
accountSecret: hardcodedUserCredentials.secret,
syncServer: "wss://mesh.jazz.tools/?key=you@example.com",
});

View File

@@ -0,0 +1,39 @@
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import { JazzClientContext } from "./jazz-client";
import { hardcodedUserCredentials } from "./hardcodedUserCredentials";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});
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`}
>
<JazzClientContext credentials={hardcodedUserCredentials}>
{children}
</JazzClientContext>
</body>
</html>
);
}

View File

@@ -0,0 +1,7 @@
import { co, CoMap } from "jazz-tools";
export class Doc extends CoMap {
title = co.string;
text = co.string;
tweet = co.string;
}

View File

@@ -0,0 +1,13 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ["jazz-tools", "jazz-nodejs", "cojson-storage-indexeddb"],
webpack: config => {
config.resolve.extensionAlias = {
".js": [".ts", ".tsx", ".js"],
};
return config;
},
};
export default nextConfig;

View File

@@ -0,0 +1,30 @@
{
"name": "jazz-example-next-ssr",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "WS_NO_BUFFER_UTIL=true next build",
"start": "WS_NO_BUFFER_UTIL=true next start",
"lint": "next lint"
},
"dependencies": {
"jazz-nodejs": "workspace:^0.8.1",
"jazz-react": "workspace:^0.8.1",
"jazz-tools": "workspace:^0.8.1",
"next": "14.2.13",
"react": "^18",
"react-dom": "^18",
"react-tweet": "^3.2.1"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.13",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"typescript": "^5"
}
}

View File

@@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;

View File

@@ -0,0 +1,19 @@
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
background: "var(--background)",
foreground: "var(--foreground)",
},
},
},
plugins: [],
};
export default config;

View File

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

View File

@@ -1,5 +1,13 @@
# jazz-password-manager
## 0.0.3
### Patch Changes
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1
## 0.0.2
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-password-manager",
"private": true,
"version": "0.0.2",
"version": "0.0.3",
"type": "module",
"scripts": {
"dev": "vite",
@@ -11,8 +11,8 @@
"clean-install": "rm -rf node_modules pnpm-lock.yaml && pnpm install"
},
"dependencies": {
"jazz-react": "workspace:0.8.0",
"jazz-tools": "workspace:0.8.0",
"jazz-react": "workspace:0.8.1",
"jazz-tools": "workspace:0.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.41.5",

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