lite: delete all

This commit is contained in:
alex 2023-04-21 16:53:31 +01:00
parent b306d7cb41
commit ec84f64e63
859 changed files with 0 additions and 167998 deletions

View file

@ -1,8 +0,0 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

View file

@ -1,10 +0,0 @@
{
"$schema": "https://unpkg.com/@changesets/config@1.6.4/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}

View file

@ -1,3 +0,0 @@
**/node_modules/*
**/out/*
**/.next/*

View file

@ -1,43 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"tsconfigRootDir": "__dirname",
"project": [
"./apps/*/tsconfig.json",
"./apps/vscode/*/tsconfig.json",
"./packages/*/tsconfig.json"
]
},
"plugins": ["@typescript-eslint", "jest"],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:jest/recommended"
],
"rules": {
"jest/no-export": "warn",
"jest/no-identical-title": "warn"
},
"overrides": [
{
// enable the rule specifically for TypeScript files
"files": ["*.ts", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-module-boundary-types": [0],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
]
}
}
]
}

1
.github/FUNDING.yml vendored
View file

@ -1 +0,0 @@
github: [steveruizok]

View file

@ -1,7 +0,0 @@
---
name: Bug Report
about: Writing and other documentation.
title: '[bug] Bug description'
labels: bug
assignees: ''
---

View file

@ -1,5 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: tldraw Beta
url: https://github.com/tldraw/tldraw-beta/issues/new
about: Is your issue for the tldraw beta? Report it on the beta repo instead.

View file

@ -1,7 +0,0 @@
---
name: Documentation
about: Writing and other documentation.
title: '[documentation] Content'
labels: documentation
assignees: ''
---

View file

@ -1,7 +0,0 @@
---
name: Feature
about: Begin discussion of a new feature.
title: '[feature] Feature or improvement'
labels: enhancement
assignees: ''
---

View file

@ -1,7 +0,0 @@
---
name: Testing
about: Tests that need to be written.
title: '[tests] Test'
labels: testing
assignees: ''
---

View file

@ -1,33 +0,0 @@
name: CI
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# turbo cache
- name: Turbo Cache
id: turbo-cache
uses: actions/cache@v2
with:
path: node_modules/.cache/turbo
key: turbo-${{ github.job }}-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
turbo-${{ github.job }}-${{ github.ref_name }}-
# install modules
- name: Install modules
run: yarn
# build
- name: Build Packages
run: yarn build:packages --cache-dir=".turbo"
# lint
- name: Lint
run: yarn lint
# run unit tests
- name: Jest Annotations & Coverage
run: yarn test:ci

20
.gitignore vendored
View file

@ -1,20 +0,0 @@
node_modules/
build/
lib/
dist/
docs/
.idea/*
.DS_Store
coverage
*.log
.vercel
.next
apps/www/public/workbox-*
apps/www/public/worker-*
apps/www/public/sw.js
apps/www/public/sw.js.map
.env
firebase.config.*.turbo
.turbo

View file

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn run pre-commit

View file

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn run pre-push

View file

@ -1,9 +0,0 @@
# Ignored Files for Search
dist
node_modules
*.d.ts
*.js
*.md
*.lock
*.tsbuildinfo

View file

@ -1,16 +0,0 @@
/.github/
/.vscode/
/node_modules/
/build/
/tmp/
.idea/*
coverage
*.log
.gitlab-ci.yml
package-lock.json
/*.tgz
/tmp*
/mnt/
/package/

View file

@ -1,18 +0,0 @@
assets
**/assets
**/coverage
**/dist
**/extension/editor
**/out
**/public
.DS_Store
.next
.tldr
.turbo
.vercel
.vsix
*.lock
*.log
*.yaml

View file

@ -1,9 +0,0 @@
{
"trailingComma": "es5",
"singleQuote": true,
"semi": false,
"printWidth": 100,
"importOrder": ["^[~]", "^[./]"],
"importOrderSortSpecifiers": true,
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"]
}

View file

@ -1,3 +0,0 @@
{
"recommendations": ["esbenp.prettier-vscode", "tldraw-org.tldraw-vscode"]
}

View file

@ -1,3 +0,0 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}

View file

@ -1,17 +0,0 @@
{
"createComment": {
"scope": "typescript,typescriptreact",
"prefix": "ccc",
"body": [
"/**",
" * ${1:description}",
" *",
" * ### Example",
" *",
" *```ts",
" * ${2:example}",
" *```"
],
"description": "comment"
}
}

View file

@ -1,80 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address, without their explicit permission
- Contacting individual members, contributors, or leaders privately, outside designated community mechanisms, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at opensource@github.com. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of actions.
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at <https://www.contributor-covenant.org/version/2/0/code_of_conduct.html>.
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at <https://www.contributor-covenant.org/faq>. Translations are available at <https://www.contributor-covenant.org/translations>.

View file

@ -1,80 +0,0 @@
# Welcome to the tldraw contributing guide <!-- omit in toc -->
Thank you for investing your time in contributing to our project! Any contribution you make will be reflected in the @tldraw/tldraw package and at [tldraw.com](https://tldraw.com).
Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR.
Use the table of contents icon on the top left corner of this document to get to a specific section of this guide quickly.
## New contributor guide
To get an overview of the project, read the [README](README.md). Here are some resources to help you get started with open source contributions:
- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github)
- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git)
- [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow)
- [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests)
## Getting started
Join the [Discord channel](https://discord.gg/SBBEVCA4PG). If you have questions or feedback, this is the best place to reach the team and other contributors directly.
### Issues
#### Create a new issue
If you spot a problem, [search if an issue already exists](https://github.com/tldraw/tldraw/issues). If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/tldraw/tldraw/issues/new/choose).
#### Solve an issue
Scan through our [existing issues](https://github.com/tldraw/tldraw/issues) to find one that interests you. You can narrow down the search using `labels` as filters. See [Labels](/contributing/how-to-use-labels.md) for more information. If you find an issue to work on, you are welcome to open a PR with a fix.
### Make Changes
#### Make changes locally
1. [Install Git LFS](https://docs.github.com/en/github/managing-large-files/versioning-large-files/installing-git-large-file-storage).
2. Fork the repository.
- Using GitHub Desktop:
- [Getting started with GitHub Desktop](https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/getting-started-with-github-desktop) will guide you through setting up Desktop.
- Once Desktop is set up, you can use it to [fork the repo](https://docs.github.com/en/desktop/contributing-and-collaborating-using-github-desktop/cloning-and-forking-repositories-from-github-desktop)!
- Using the command line:
- [Fork the repo](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#fork-an-example-repository) so that you can make your changes without affecting the original project until you're ready to merge them.
- GitHub Codespaces:
- [Fork, edit, and preview](https://docs.github.com/en/free-pro-team@latest/github/developing-online-with-codespaces/creating-a-codespace) using [GitHub Codespaces](https://github.com/features/codespaces) without having to install and run the project locally.
3. Install or update to **Node.js v16**.
4. Create a working branch and start with your changes!
5. Follow the [the development guide](guides/development.md).
### Commit your update
Commit the changes once you are happy with them.
### Pull Request
When you're finished with the changes, create a pull request, also known as a PR.
- Fill the "Ready for review" template so that we can review your PR. This template helps reviewers understand your changes as well as the purpose of your pull request.
- Don't forget to [link PR to issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) if you are solving one.
- Enable the checkbox to [allow maintainer edits](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork) so the branch can be updated for a merge.
Once you submit your PR, a team member will review your proposal. We may ask questions or request for additional information.
- We may ask for changes to be made before a PR can be merged, either using [suggested changes](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/incorporating-feedback-in-your-pull-request) or pull request comments. You can apply suggested changes directly through the UI. You can make any other changes in your fork, then commit them to your branch.
- As you update your PR and apply changes, mark each conversation as [resolved](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request#resolving-conversations).
- If you run into any merge issues, checkout this [git tutorial](https://lab.github.com/githubtraining/managing-merge-conflicts) to help you resolve merge conflicts and other issues.
### Your PR is merged!
Congratulations :tada::tada: The tldraw team thanks you :sparkles:.
Once your PR is merged, your contributions will become part of the next tldraw release, and will be visible in the [tldraw app](https://tldraw.com).

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 tldraw GB Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,74 +0,0 @@
> **Note** We're between versions! The code in this repository is for the **original version** of tldraw, which is hosted at [old.tldraw.com](https://old.tldraw.com). The new version (hosted at [tldraw.com](https://tldraw.com)) is not yet open source. It is _distributed_ however, and you can read more about the new version on **the new docs site** at [docs.tldraw.dev](https://docs.tldraw.dev). This should all be cleaned up soon. 🚧
---
<div style="text-align: center; transform: scale(.5);">
<img src="https://github.com/tldraw/tldraw/raw/main/assets/card-repo.png"/>
</div>
![A screenshot of the tldraw web app](./assets/screenshot.png)
Welcome to the [tldraw](https://tldraw.com) monorepo.
🙌 Questions? Join the [Discord channel](https://discord.gg/SBBEVCA4PG) or start a [discussion](https://github.com/tldraw/tldraw/discussions/new).
💕 Love this project? Consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok).
Thanks to our corporate sponsors:
<div style="display: flex; flex-wrap: wrap; gap: 32px;">
<a href="https://sentry.io"><img src="./assets/sentry.svg"></img></a>
<a href="https://vercel.com/?utm_source=team-slug&utm_campaign=oss"><img src="./assets/vercel.svg"></img></a>
<a href="https://oppizi.com"><img src="./assets/oppizi.png" width="212"></img></a>
<a href="https://logseq.com"><img src="./assets/logseq.svg" width="80"></img></a>
<a href="https://blindsidenetworks.com/"><img src="./assets/blindside.png" width="212"></img></a>
<a href="https://www.100ms.live/"><img src="./assets/100ms.png" width="212"></img></a>
</div>
...and to our [individual sponsors](https://github.com/sponsors/steveruizok#sponsors)!
## Contents
This repository is a monorepo containing two packages:
- [**packages/tldraw**](https://github.com/tldraw/tldraw/tree/main/packages/tldraw) contains the source for the [@tldraw/tldraw](https://www.npmjs.com/package/@tldraw/tldraw) package. This is an editor as a React component named `<Tldraw>`. You can use this package to embed the tldraw editor in any React application.
- [**packages/core**](https://github.com/tldraw/tldraw/tree/main/packages/core) contains the source for the [@tldraw/core](https://www.npmjs.com/package/@tldraw/core) package. This is a renderer for React components in a canvas-style UI. It is used by `@tldraw/tldraw` as well as several other projects.
...and two apps:
- [**apps/www**](https://github.com/tldraw/tldraw/tree/main/apps/www) contains the source for the [tldraw.com](https://tldraw.com) website.
- [**apps/vscode**](https://github.com/tldraw/tldraw/tree/main/apps/vscode) contains the source for the [tldraw VS Code extension](https://marketplace.visualstudio.com/items?itemName=tldraw-org.tldraw-vscode).
...and three examples:
- [**examples/core-example**](https://github.com/tldraw/tldraw/tree/main/examples/core-example) is a simple example for `@tldraw/core`.
- [**examples/core-example-advanced**](https://github.com/tldraw/tldraw/tree/main/examples/core-example-advanced) is a second example for `@tldraw/core`.
- [**examples/tldraw-example**](https://github.com/tldraw/tldraw/tree/main/examples/tldraw-example) is an example for `@tldraw/tldraw`.
## Discussion
Want to connect? Visit the [Discord channel](https://discord.gg/SBBEVCA4PG).
## Contribution
Interested in contributing? See the [contributing guide](/CONTRIBUTING.md).
## Support
Need help? Please [open an issue](https://github.com/tldraw/tldraw/issues/new) for support.
## License
This project is licensed under MIT.
If you're using the library in a commercial product, please consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok).
## Author
- [@steveruizok](https://twitter.com/steveruizok)

View file

@ -1,55 +0,0 @@
# @tldraw/vscode
This folder contains the source for the tldraw VS Code extension.
## Developing
## 1. Install dependencies
- Run `yarn` from the root folder
## 2. Build @tldraw/tldraw
- Run `yarn build:packages` from the root folder.
## 3. Start the editor
In the root folder:
- Run `yarn start:vscode`.
This will start the development server for the `vscode/editor` project and open the `vscode/extension` folder in a new window.
In the `vscode/extension` window, open the terminal and run:
- Install dependencies (`yarn`)
- Start the VS Code debugger (Menu > Run > Start Debugging)
Open a `.tldr` file or create a new `.tldr` file from the command palette.
## Publishing
To publish, chat with the team on the [Discord channel](https://discord.gg/SBBEVCA4PG).
- Install `vsce` globally
- Run `vsce login tldraw-org` and sign in
In the `vscode/extension` folder:
- Run `yarn vscode:publish`
#### References
- [VS Code Marketplace Manager](https://marketplace.visualstudio.com/manage/)
- [Web Extensions Guide](https://code.visualstudio.com/api/extension-guides/web-extensions)
- [Test Your Web Extension](https://code.visualstudio.com/api/extension-guides/web-extensions#test-your-web-extension)
- [Web Extension Testing](https://code.visualstudio.com/api/extension-guides/web-extensions#web-extension-tests)
- An example custom editor that does work as a Web Extension
- https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio
- https://github.com/hediet/vscode-drawio
- [VS Code Extension API/Landing Page](https://code.visualstudio.com/api)
- [Getting Started](https://code.visualstudio.com/api/get-started/your-first-extension)
- [Custom Editor API](https://code.visualstudio.com/api/extension-guides/custom-editors)
- [github.com/microsoft/vscode-extension-samples](https://github.com/microsoft/vscode-extension-samples)
- [Extensions Guide -> Webviews](https://code.visualstudio.com/api/extension-guides/webview)
- [Publishing Extensions](https://code.visualstudio.com/api/working-with-extensions/publishing-extension)

View file

@ -1,134 +0,0 @@
# @tldraw/vscode-editor
## 1.15.2
### Patch Changes
- Include clipboard fixes.
## 1.15.1
### Patch Changes
- Fix clipboard stealing focus.
## 1.15.0
### Minor Changes
- - Fixes copy as PNG
- Fixes a bug with copy and paste
- Fixes a bug on iPad while using pencil
- Fixes a bug with the style menus
- Fixes a bug with image export
- Updates translations
## 1.14.0
### Minor Changes
- - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates German translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
## 1.13.1
### Patch Changes
- - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates German translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
- 12c0b2ac: - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
## 1.13.0
### Minor Changes
- - Adds missing Arabic translations for dialogs. @abedshamia
- Updates core-example. @brydenfogelman
- Updates Polish translations. @adan2013
- Adds missing Aria-Labels. @KDSBrowne
- Improves Japanese translation. @yashkumarbarot
- Fixes height and width in app.viewport. @hiroshisuga
- Improves labels on StlyeMenu @proke03
- Adds missing tooltips to undo / redo buttons. @proke03
## 1.12.0
### Minor Changes
- - Improve middle mouse panning
- Fix bug with assets in VS Code plugin
- Improve performance of draw-style shapes
- Fix bug with creating assets
- Fix bug with text align in labels when outputting images
- Fix bug with middle mouse panning on Linux
- Fix bug with zoom shortcuts on number pad
- Fix bug with draw and erase direction when holding shift
## 1.11.0
### Minor Changes
- d919bd27: Bump dependencies, add international support.
## 1.11.0-next.0
### Minor Changes
- Bump dependencies, add international support.
## 1.10.2
### Patch Changes
- Fix tldraw assets for vscode extension.
## 1.10.1
### Patch Changes
- Fix build.
## 1.10.0
### Minor Changes
- Fix build error in extension.
## 1.9.0
### Minor Changes
- Bump underlying packages.
## 1.8.0
### Minor Changes
- c09d6a3a: Adds text field for page rename, undo buttons on all screen sizes, arrow behavior with alt key.
## 1.7.1
### Patch Changes
- Fix bug with missing parents / children.

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Stephen Ruiz Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,9 +0,0 @@
<div style="text-align: center; transform: scale(.5);">
<img src="https://github.com/tldraw/tldraw/raw/main/assets/card-repo.png"/>
</div>
# @tldraw/vscode-editor
The app for the tldraw VS Code Extension.
See the README at `vscode` for more about this project.

View file

@ -1,35 +0,0 @@
{
"name": "@tldraw/vscode-editor",
"version": "1.15.2",
"private": true,
"description": "An an editor for the tldraw vscode extension.",
"author": "@steveruizok",
"license": "MIT",
"keywords": [
"react",
"typescript",
"esbuild"
],
"scripts": {
"dev": "node scripts/dev.mjs -w",
"build": "node scripts/build.mjs",
"lint": "TIMING=1 eslint src/ --ext .ts,.tsx",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
},
"devDependencies": {
"@tldraw/tldraw": "*",
"@types/node": "^17.0.14",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.1.8",
"concurrently": "7.0.0",
"create-serve": "1.0.1",
"esbuild": "^0.14.54",
"esbuild-serve": "^1.0.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tslib": "^2.4.0",
"typescript": "^4.7.3"
},
"gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6"
}

View file

@ -1,57 +0,0 @@
/* eslint-disable */
import esbuild from 'esbuild'
import fs from 'fs'
import { createRequire } from 'module'
import path from 'path'
const pkg = createRequire(import.meta.url)('../package.json')
const { log: jslog } = console
async function main() {
if (fs.existsSync('./dist')) {
fs.rmSync('./dist', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
if (!fs.existsSync('./dist')) {
fs.mkdirSync('./dist')
}
fs.readdirSync('./src/public').forEach((file) =>
fs.copyFile(path.join('./src/public', file), path.join('./dist', file), (err) => {
if (err) throw err
})
)
try {
esbuild.buildSync({
entryPoints: ['./src/index.tsx'],
outfile: 'dist/index.js',
minify: false,
bundle: true,
format: 'esm',
target: 'es6',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
tsconfig: './tsconfig.json',
define: {
'process.env.NODE_ENV': '"production"',
},
loader: {
'.woff2': 'dataurl',
'.woff': 'dataurl',
},
})
jslog(`${pkg.name}: Build completed.`)
} catch (e) {
jslog(`× ${pkg.name}: Build failed due to an error.`)
jslog(e)
}
}
main()

View file

@ -1,65 +0,0 @@
/* eslint-disable no-undef */
import dotenv from 'dotenv'
import esbuildServe from 'esbuild-serve'
import fs from 'fs'
import path from 'path'
dotenv.config()
const { log: jslog } = console
async function main() {
if (fs.existsSync('./dist')) {
fs.rmSync('./dist', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
if (!fs.existsSync('./dist')) {
fs.mkdirSync('./dist')
}
fs.readdirSync('./src/public').forEach((file) =>
fs.copyFile(path.join('./src/public', file), path.join('./dist', file), (err) => {
if (err) throw err
})
)
try {
await esbuildServe(
{
entryPoints: ['src/index.tsx'],
outfile: 'dist/index.js',
minify: false,
bundle: true,
incremental: true,
target: 'es6',
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment',
loader: {
'.woff2': 'dataurl',
'.woff': 'dataurl',
},
define: {
'process.env.NODE_ENV': '"production"',
},
watch: {
onRebuild(err) {
err ? error('❌ Failed') : jslog('✅ Updated')
},
},
},
{
port: 5420,
root: './dist',
live: true,
}
)
} catch (err) {
process.exit(1)
}
}
main()

View file

@ -1,77 +0,0 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { TDDocument, TDFile, Tldraw, TldrawApp } from '@tldraw/tldraw'
import * as React from 'react'
import type { MessageFromExtension, MessageFromWebview } from './types'
import { defaultDocument } from './utils/defaultDocument'
import { vscode } from './utils/vscode'
// Will be placed in global scope by extension
declare let currentFile: TDFile
declare let assetSrc: string
const App = () => {
const rLoaded = React.useRef(false)
const rTldrawApp = React.useRef<TldrawApp>()
const rInitialDocument = React.useRef<TDDocument>(
currentFile ? currentFile.document : defaultDocument
)
// When the editor mounts, save the state instance in a ref.
const handleMount = React.useCallback((app: TldrawApp) => {
TldrawApp.assetSrc = assetSrc ?? 'tldraw-assets.json'
rTldrawApp.current = app
}, [])
// When the editor's document changes, post the stringified document to the vscode extension.
const handlePersist = React.useCallback((app: TldrawApp) => {
vscode.postMessage({
type: 'editorUpdated',
text: JSON.stringify({
...currentFile,
document: app.document,
assets: {},
} as TDFile),
} as MessageFromWebview)
}, [])
// When the file changes from VS Code's side, update the editor's document.
React.useEffect(() => {
function handleMessage({ data }: MessageEvent<MessageFromExtension>) {
if (data.type === 'openedFile') {
try {
const { document } = JSON.parse(data.text) as TDFile
const app = rTldrawApp.current!
if (rLoaded.current) {
app.updateDocument(document)
} else {
app.loadDocument(document)
rLoaded.current = true
}
app.zoomToFit()
} catch (e) {
console.warn('Failed to parse file:', data.text)
}
}
}
window.addEventListener('message', handleMessage)
return () => {
window.removeEventListener('message', handleMessage)
}
})
return (
<div className="tldraw">
<Tldraw
id={rInitialDocument.current.id}
document={rInitialDocument.current}
onMount={handleMount}
onPersist={handlePersist}
autofocus
/>
</div>
)
}
export default App

View file

@ -1,10 +0,0 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import App from './app'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)

View file

@ -1,20 +0,0 @@
html,
* {
box-sizing: border-box;
}
body {
overscroll-behavior: none;
margin: 0px;
padding: 0px;
}
.tldraw {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
width: 100%;
height: 100%;
}

View file

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="index.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>tldraw</title>
</head>
<body>
<div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script type="module" src="./index.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -1,14 +0,0 @@
export type MessageFromWebview = {
type: 'editorUpdated'
text: string
}
export type MessageFromExtension =
| {
type: 'openedFile'
text: string
}
| {
type: 'fileSaved'
text: string
}

View file

@ -1,27 +0,0 @@
import { TDDocument, TldrawApp } from '@tldraw/tldraw'
export const defaultDocument: TDDocument = {
id: 'doc',
name: 'New Document',
version: TldrawApp.version,
pages: {
page: {
id: 'page',
name: 'Page 1',
childIndex: 1,
shapes: {},
bindings: {},
},
},
assets: {},
pageStates: {
page: {
id: 'page',
selectedIds: [],
camera: {
point: [0, 0],
zoom: 1,
},
},
},
}

View file

@ -1,29 +0,0 @@
import { TDExport } from '@tldraw/tldraw'
export const EXPORT_ENDPOINT =
process.env.NODE_ENV === 'development'
? 'http://localhost:3000/api/export'
: 'https://www.tldraw.com/api/export'
export async function exportToImage(info: TDExport) {
if (info.serialized) {
const link = document.createElement('a')
link.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(info.serialized)
link.download = info.name + '.' + info.type
link.click()
return
}
const response = await fetch(EXPORT_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(info),
})
const blob = await response.blob()
const blobUrl = URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = blobUrl
link.download = info.name + '.' + info.type
link.click()
}

View file

@ -1,8 +0,0 @@
import type { MessageFromWebview } from '../types'
// Will be placed in global scope by extension
declare function acquireVsCodeApi(): {
postMessage(options: MessageFromWebview): void
}
export const vscode = acquireVsCodeApi()

View file

@ -1,20 +0,0 @@
{
"extends": "../../../tsconfig.base.json",
"include": ["src"],
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"outDir": "./dist",
"rootDir": "src",
"baseUrl": "src",
"emitDeclarationOnly": false,
"jsx": "react-jsx",
"paths": {
"@tldraw/tldraw": ["../../../packages/tldraw"]
}
},
"references": [
{
"path": "../../../packages/tldraw"
}
]
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,6 +0,0 @@
dist
editor
node_modules
.vscode-test-web/
*.vsix
.DS_Store

View file

@ -1,5 +0,0 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"]
}

View file

@ -1,24 +0,0 @@
// A launch configuration that compiles the extension and then opens it inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Run Web Extension ",
"type": "pwa-extensionHost",
"request": "launch",
"program": "${workspaceFolder}/src/extension.ts",
"cwd": "${workspaceFolder}",
"args": [
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}",
"${workspaceFolder}/src/extension.ts"
],
"outFiles": ["${workspaceFolder}/dist/web/**/*.js", "!**/node_modules/**"],
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
"sourceMaps": true
}
]
}

View file

@ -1,11 +0,0 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
"search.exclude": {
"out": true // set this to false to include "out" folder in search results
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off"
}

View file

@ -1,390 +0,0 @@
## 1.2.4
## 1.28.4
### Patch Changes
- Include clipboard fixes.
## 1.28.3
### Patch Changes
- Fix clipboard stealing focus.
## 1.28.0
### Minor Changes
- - Fixes copy as PNG
- Fixes a bug with copy and paste
- Fixes a bug on iPad while using pencil
- Fixes a bug with the style menus
- Fixes a bug with image export
- Updates translations
## 1.27.0
### Minor Changes
- - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates German translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
## 1.26.1
### Patch Changes
- - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates German translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
- 12c0b2ac: - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
## 1.26.0
### Minor Changes
- - Adds missing Arabic translations for dialogs. @abedshamia
- Updates core-example. @brydenfogelman
- Updates Polish translations. @adan2013
- Adds missing Aria-Labels. @KDSBrowne
- Improves Japanese translation. @yashkumarbarot
- Fixes height and width in app.viewport. @hiroshisuga
- Improves labels on StlyeMenu @proke03
- Adds missing tooltips to undo / redo buttons. @proke03
## 1.25.2
### Patch Changes
- Fix types in core.
## 1.25.1
### Patch Changes
- Fixes blurring text inputs in multiplayer.
## 1.25.0
### Minor Changes
- Add metadata property to user.
## 1.24.0
### Minor Changes
- - Adds `components` prop to Tldraw component (for custom Cursor, etc) @jamesbvaughan
- Adds Thai language @watchakorn-18k
- Fix event bug on `onRightPointCanvas`
- Fix bug with bad data in document with up-to-date version number
- Fix bug with arrow bindings
- Improves freehand line performance
- Improves performance of shape tree
- Improved .tldr file size (strip white space)
## 1.23.5
### Patch Changes
- Fix mouse events.
## 1.23.4
### Patch Changes
- Fix menu bug.
## 1.23.3
### Patch Changes
- Small bump.
## 1.23.2
### Patch Changes
- Fix bug with scrolling.
## 1.23.1
### Patch Changes
- - Fix bug with mouse button state
## 1.23.0
### Minor Changes
- - Remove `mobx` and `mobx-react-lite` as dependencies. This is a breaking change for libraries that expect data to be observable in `@tldraw/core`.
## 1.22.0
### Minor Changes
- - Improve middle mouse panning
- Fix bug with assets in VS Code plugin
- Improve performance of draw-style shapes
- Fix bug with creating assets
- Fix bug with text align in labels when outputting images
- Fix bug with middle mouse panning on Linux
- Fix bug with zoom shortcuts on number pad
- Fix bug with draw and erase direction when holding shift
## 1.21.1
### Patch Changes
- Remove share by URL.
## 1.21.0
### Minor Changes
- - Fix broken VS Code extension
- Add share by URL
## 1.20.0
### Minor Changes
- - Improve text (and multiline text) in image exports
- Create European Portugese translation
- Create Swedish translation
- Use system default for theme default
- Update translation label for Chinese
- Fix bugs with flip command
- Fix bug with duplicate page command
- Improve dialogs
- Improve SVG pasting
## 1.19.0
### Minor Changes
- - restores the sponsor link
- removes sign in / sign out / authentication / next-auth
- removes sponsorware page
- removes unused translation keys
- fixes dark mode on help icon
- improves border radius on panels
- fixes dividers on panels
- removes animated cursors (replace with CSS transitions for performance when - many cursors are present)
- removes unused icons
- adds migration for export default background option
- correctly normalizes mouse wheel
## 1.18.0
### Minor Changes
- - Adds Ukrainian translations
- Adds Farsi translation
- Adds Hebrew translation
- Adds option for dock position
- Improves page numbering
- Support dark mode in menus
- Make language menu scrollable
- Adds link to translation guide
## 1.17.2
### Patch Changes
- Improve page reordering, add german translation
## 1.17.1
### Patch Changes
- Add additional translations.
## 1.17.0
### Minor Changes
- 8ef86c19: - Updates multiplayer implementation.
- Adds translation guide.
- Fixes bug on text shape
- Updates undo redo for text shapes.
## 1.16.2
### Patch Changes
- Replace multiplayer icon.
## 1.16.1
### Patch Changes
- Fix clipboard bug in Firefox, add overwite option to `insertContent`.
## 1.16.0
### Minor Changes
- Add getContent / insertContent, improve copy and paste position logic
## 1.15.0
### Minor Changes
- d919bd27: Bump dependencies, add international support.
### Patch Changes
- Add internationalization, improve readonly mode, bump dependencies for React 18
## 1.15.0-next.0
### Minor Changes
- Bump dependencies, add international support.
## 1.14.1
### Patch Changes
- Improve eraser scribble.
## 1.14.0
### Minor Changes
- Add erase line, bump dependencies.
## 1.13.3
### Patch Changes
- Fix keyboard events when style menu is open.
## 1.13.2
### Patch Changes
- Move style panel to right corner.
## 1.13.1
### Patch Changes
- Add option to keep style panel open.
## 1.13.0
### Minor Changes
- Fixes zooming and pinching bugs. Adds ErrorBoundary to Tldraw component. Cleans up sponosrship feature in menu.
## 1.12.6
### Patch Changes
- Improve image export for files that include scaled or rotated text.
## 1.12.5
### Patch Changes
- Improve clipboard, SVG text.
## 1.12.4
### Patch Changes
- Fix export on dark mode.
## 1.12.3
### Patch Changes
- Fix clipboard events in editing text in vscode extension, fix outline for editing text in vscode extension.
## 1.12.2
### Patch Changes
- Update to include 1.12.2.
## 1.12.1
### Patch Changes
- Fix tldraw assets for vscode extension.
## 1.12.0
### Minor Changes
- This update changes how clipboard actions (cut, copy, paste) and exports work. Significantly, image exports are no longer handled via a server-side integration, and are instead handled locally on the client. This allows now for exports in the VS Code extension, as well as greatly simplifying exports for apps that embed the Tldraw React component.
## 1.11.3
### Patch Changes
- Add paste for assets.
## 1.11.2
### Patch Changes
- Fix build.
## 1.10.0
### Minor Changes
- Bump underlying packages.
## 1.9.0
### Minor Changes
- c09d6a3a: Adds text field for page rename, undo buttons on all screen sizes, arrow behavior with alt key.
## 1.8.4
### Patch Changes
- Fix bug with missing parents / children.
- Fixed bug that prevented saving.
## 1.1.9
- Updates READMEs.
## 1.1.6
- Fixes bugs in VS Code extension.
## 0.1.23
- Fixing bugs related to saving files.
## 0.1.0
- Launched!

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Stephen Ruiz Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,30 +0,0 @@
## Introduction
Create and edit diagrams using the [tldraw](https://tldraw.com/) editor, all inside of VS Code.
![A screenshot of tldraw in VS Code](./assets/screenshot.png)
[tldraw](https://tldraw.com) is a free drawing and diagramming tool with a hand-drawn style and convenient features such as smart arrows, snapping, and sticky notes. With the tldraw extension for VS Code, your tldraw files can be version controlled alongside your code.
![A recording of tldraw in VS Code](./assets/recording.gif)
> **Tip:** The files you create or edit here can also be opened in the tldraw [web app](https://tldraw.com).
## Features
1. View, edit and save tldraw files (`.tldr`)
## Usage
- To view an existing tldraw file, open a file with the `.tldr` extension in VS Code.
- To create a new tldraw file, use the provided command: "tldraw: New tldraw File".
## Community
### Support
Need help? Please [open an issue](https://github.com/tldraw/tldraw/issues/new/choose) for support.
### Discussion
Want to connect with other devs? Visit the [Discord channel](https://discord.gg/SBBEVCA4PG).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

View file

@ -1,168 +0,0 @@
{
"fileHandle": null,
"document": {
"id": "doc",
"name": "New Document",
"version": 15.3,
"pages": {
"page": {
"id": "page",
"name": "Page 1",
"childIndex": 1,
"shapes": {
"3805a6e3-b50a-4bb2-0782-e687526cafc8": {
"id": "3805a6e3-b50a-4bb2-0782-e687526cafc8",
"type": "rectangle",
"name": "Rectangle",
"parentId": "page",
"childIndex": 1,
"point": [
245.96,
277.88
],
"size": [
292.43,
125.76
],
"rotation": 0,
"style": {
"color": "white",
"size": "small",
"isFilled": false,
"dash": "draw"
},
"label": "Rectangles with labels"
},
"9a20ffa8-044b-4ca3-0448-632e2b2831d1": {
"id": "9a20ffa8-044b-4ca3-0448-632e2b2831d1",
"type": "ellipse",
"name": "Ellipse",
"parentId": "page",
"childIndex": 3,
"point": [
995.24,
235.11
],
"radius": [
112.92500000000001,
108.96000000000004
],
"rotation": 0,
"style": {
"color": "white",
"size": "small",
"isFilled": true,
"dash": "draw",
"scale": 1
},
"label": "Ovals with labels",
"labelPoint": [
0.5,
0.5
]
},
"c2125c4e-e9ef-4eeb-2011-9e8aaeadd6ea": {
"id": "c2125c4e-e9ef-4eeb-2011-9e8aaeadd6ea",
"type": "arrow",
"name": "Arrow",
"parentId": "page",
"childIndex": 4,
"point": [
538.39,
341.56
],
"rotation": 0,
"bend": -0.000013369615345367926,
"handles": {
"start": {
"id": "start",
"index": 0,
"point": [
0,
0
],
"canBind": true,
"bindingId": "31007b26-4667-4932-00aa-7f389642b187"
},
"end": {
"id": "end",
"index": 1,
"point": [
448.85,
2.44
],
"canBind": true,
"bindingId": "7b099540-f8b1-4bf3-0d7d-2b74df370067"
},
"bend": {
"id": "bend",
"index": 2,
"point": [
224.43,
1.22
]
}
},
"decorations": {
"end": "arrow"
},
"style": {
"color": "white",
"size": "small",
"isFilled": false,
"dash": "draw",
"scale": 1
},
"label": "Arrows with labels",
"labelPoint": [
0.5,
0.5
]
}
},
"bindings": {
"7b099540-f8b1-4bf3-0d7d-2b74df370067": {
"id": "7b099540-f8b1-4bf3-0d7d-2b74df370067",
"type": "arrow",
"fromId": "c2125c4e-e9ef-4eeb-2011-9e8aaeadd6ea",
"toId": "9a20ffa8-044b-4ca3-0448-632e2b2831d1",
"handleId": "end",
"point": [
0.08,
0.5
],
"distance": 8
},
"31007b26-4667-4932-00aa-7f389642b187": {
"id": "31007b26-4667-4932-00aa-7f389642b187",
"type": "arrow",
"fromId": "c2125c4e-e9ef-4eeb-2011-9e8aaeadd6ea",
"toId": "3805a6e3-b50a-4bb2-0782-e687526cafc8",
"handleId": "start",
"point": [
0.5,
0.5
],
"distance": 16
}
}
}
},
"pageStates": {
"page": {
"id": "page",
"selectedIds": [],
"camera": {
"point": [
0,
0
],
"zoom": 1
},
"editingId": null
}
},
"assets": {}
},
"assets": {}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

View file

@ -1,136 +0,0 @@
{
"name": "tldraw-vscode",
"displayName": "tldraw",
"description": "The tldraw Extension for VS Code.",
"version": "1.28.4",
"license": "MIT",
"publisher": "tldraw-org",
"repository": {
"type": "git",
"url": "https://github.com/tldraw/tldraw"
},
"engines": {
"vscode": "^1.59.0"
},
"keywords": [
"diagram",
"draw",
"drawing",
"sketch",
"design",
"documentation",
"tldraw"
],
"icon": "icon.png",
"galleryBanner": {
"color": "#1d1d1d",
"theme": "dark"
},
"categories": [
"Visualization"
],
"activationEvents": [
"onCustomEditor:tldraw.tldr",
"onCommand:tldraw.tldr.new"
],
"browser": "./dist/web/extension.js",
"main": "./dist/web/extension.js",
"extensionKind": [
"workspace"
],
"contributes": {
"customEditors": [
{
"viewType": "tldraw.tldr",
"displayName": "tldraw",
"selector": [
{
"filenamePattern": "*.tldr"
},
{
"filenamePattern": "*.tldr.json"
}
]
}
],
"keybindings": [
{
"key": "ctrl+shift+d",
"mac": "cmd+shift+d",
"title": "Toggle Dark Mode",
"command": "tldraw.tldr.toggleDarkMode",
"category": "tldraw",
"when": "resourceExtname == .tldr"
},
{
"key": "ctrl+numpad_add",
"mac": "cmd+numpad_add",
"title": "Zoom In",
"command": "tldraw.tldr.zoomIn",
"category": "tldraw",
"when": "resourceExtname == .tldr"
},
{
"key": "ctrl+=",
"mac": "cmd+=",
"title": "Zoom In",
"command": "tldraw.tldr.zoomIn",
"category": "tldraw",
"when": "resourceExtname == .tldr"
},
{
"key": "ctrl+numpad_subtract",
"mac": "cmd+numpad_subtract",
"title": "Zoom Out",
"command": "tldraw.tldr.zoomOut",
"category": "tldraw",
"when": "resourceExtname == .tldr"
},
{
"key": "ctrl+-",
"mac": "cmd+-",
"title": "Zoom Out",
"command": "tldraw.tldr.zoomOut",
"category": "tldraw",
"when": "resourceExtname == .tldr"
},
{
"key": "ctrl+numpad0",
"mac": "cmd+numpad0",
"title": "Reset Zoom",
"command": "tldraw.tldr.resetZoom",
"category": "tldraw",
"when": "resourceExtname == .tldr"
}
],
"commands": [
{
"command": "tldraw.tldr.new",
"title": "New File",
"category": "tldraw"
}
]
},
"scripts": {
"dev": "node scripts/dev",
"build": "node scripts/build",
"web": "vscode-test-web --browserType=chromium --extensionDevelopmentPath=.",
"package": "node scripts/package",
"publish": "vsce publish",
"lint": "TIMING=1 eslint src/ --ext ts",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist && rm -rf editor && rm -rf temp"
},
"devDependencies": {
"@tldraw/tldraw": "*",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"assert": "^2.0.0",
"mocha": "^9.1.1",
"process": "^0.11.10",
"ts-loader": "^9.2.5",
"tslib": "^2.4.0",
"typescript": "^4.7.3",
"vsce": "^2.2.0"
},
"gitHead": "4b1137849ad07da36fc8f0f19cb64e7535a79296"
}

View file

@ -1,70 +0,0 @@
/* eslint-disable */
const fs = require('fs')
const pkg = require('../package.json')
const esbuild = require('esbuild')
const { exec } = require('child_process')
const { log: jslog } = console
async function copyEditor() {
if (fs.existsSync('./editor')) {
fs.rmSync('./editor', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
try {
exec(`cp -r ../editor/dist editor;`, (error, stdout, stderr) => {
if (error) {
throw new Error(error.message)
}
if (stderr && stderr.search('warning') !== 0) {
throw new Error(stderr)
}
})
} catch (e) {
jslog(`× ${pkg.name}: Build failed due to an error.`)
jslog(e)
}
}
async function main() {
await copyEditor()
if (fs.existsSync('./dist')) {
fs.rmSync('./dist', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
try {
esbuild.buildSync({
entryPoints: ['./src/extension.ts'],
outdir: 'dist/web',
minify: false,
bundle: true,
format: 'cjs',
target: 'es6',
platform: 'node',
define: {
'process.env.NODE_ENV': '"production"',
},
tsconfig: './tsconfig.json',
external: ['vscode'],
loader: {
'.woff2': 'dataurl',
'.woff': 'dataurl',
},
})
jslog(`Built package.`)
} catch (e) {
jslog(`× Build failed due to an error.`)
jslog(e)
}
}
main()

View file

@ -1,46 +0,0 @@
/* eslint-disable */
const fs = require('fs')
const esbuild = require('esbuild')
const { log: jslog } = console
async function main() {
if (fs.existsSync('./dist')) {
fs.rmSync('./dist', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
try {
await esbuild.build({
entryPoints: ['./src/extension.ts'],
outdir: 'dist/web',
minify: false,
bundle: true,
format: 'cjs',
target: 'es6',
sourcemap: 'inline',
platform: 'node',
define: {
'process.env.NODE_ENV': '"development"',
},
tsconfig: './tsconfig.json',
external: ['vscode'],
incremental: true,
watch: {
onRebuild(err) {
err ? console.error('❌ Failed') : jslog('✅ Updated')
},
},
})
jslog(`Built package.`)
} catch (e) {
jslog(`× Build failed due to an error.`)
jslog(e)
}
}
main()

View file

@ -1,45 +0,0 @@
/* eslint-disable */
//const version = require('../../../lerna.json').version
const fs = require('fs')
const pkg = require('../package.json')
const { exec } = require('child_process')
const { log: jslog } = console
async function main() {
if (fs.existsSync('./editor')) {
fs.rmSync('./editor', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
if (fs.existsSync('./temp')) {
fs.rmSync('./temp', { recursive: true }, (e) => {
if (e) {
throw e
}
})
}
fs.mkdirSync('./temp')
try {
exec(
`cp -r ../editor/dist editor; vsce package; mv ${pkg.name}-${pkg.version}.vsix ${'./temp'}`,
(error, stdout, stderr) => {
if (error) {
throw new Error(error.message)
}
if (stderr && stderr.search('warning') !== 0) {
throw new Error(stderr)
}
}
)
} catch (e) {
jslog(`× ${pkg.name}: Build failed due to an error.`)
jslog(e)
}
}
main()

View file

@ -1,62 +0,0 @@
import * as vscode from 'vscode'
import { TldrawWebviewManager } from './TldrawWebviewManager'
/**
* The Tldraw extension's editor uses CustomTextEditorProvider, which means
* it's underlying model from VS Code's perspective is a text file. We likely
* will switch to CustomEditorProvider which gives us more control but will require
* more book keeping on our part.
*/
export class TldrawEditorProvider implements vscode.CustomTextEditorProvider {
constructor(private readonly context: vscode.ExtensionContext) {}
private static newTDFileId = 1
private static readonly viewType = 'tldraw.tldr'
public static register = (context: vscode.ExtensionContext): vscode.Disposable => {
// Several commands exist only to prevent the default keyboard shortcuts
const noopCmds = ['zoomIn', 'zoomOut', 'resetZoom', 'toggleDarkMode']
noopCmds.forEach((name) =>
vscode.commands.registerCommand(`${this.viewType}.${name}`, () => null)
)
// Register the 'Create New File' command, which creates a temporary
// .tldr file and opens it in the editor.
vscode.commands.registerCommand(`${this.viewType}.new`, () => {
const id = this.newTDFileId++
const name = id > 1 ? `New Document ${id}.tldr` : `New Document.tldr`
const workspaceFolders = vscode.workspace.workspaceFolders
const path = workspaceFolders ? workspaceFolders[0].uri : vscode.Uri.parse('')
vscode.commands.executeCommand(
'vscode.openWith',
vscode.Uri.joinPath(path, name).with({ scheme: 'untitled' }),
this.viewType
)
})
// Register our editor provider, indicating to VS Code that we can
// handle files with the .tldr extension.
return vscode.window.registerCustomEditorProvider(
this.viewType,
new TldrawEditorProvider(context),
{
webviewOptions: {
retainContextWhenHidden: true,
},
supportsMultipleEditorsPerDocument: true,
}
)
}
// When our custom editor is opened, create a TldrawWebviewManager to
// configure the webview and set event listeners to handle events.
public async resolveCustomTextEditor(
document: vscode.TextDocument,
webviewPanel: vscode.WebviewPanel
): Promise<void> {
new TldrawWebviewManager(this.context, document, webviewPanel)
}
}

View file

@ -1,175 +0,0 @@
import { TDFile } from '@tldraw/tldraw'
import * as vscode from 'vscode'
import { MessageFromExtension, MessageFromWebview } from './types'
/**
* When a new editor is opened, an instance of this class will
* be created to configure the webview and handle its events.
*/
export class TldrawWebviewManager {
private disposables: vscode.Disposable[] = []
constructor(
private context: vscode.ExtensionContext,
private document: vscode.TextDocument,
private webviewPanel: vscode.WebviewPanel
) {
// Configure the webview. For now all we do is enable scripts and also
// provide the initial webview's html content.
Object.assign(webviewPanel.webview, {
options: { enableScripts: true },
html: this.getHtmlForWebview(),
})
// Listen for changes to the document when saved from VS Code.m
vscode.workspace.onDidSaveTextDocument(
this.handleDidSaveTextDocument,
undefined,
this.disposables
)
// Listen for changes made to the text document by VS Code or by some other app.
vscode.workspace.onDidChangeTextDocument(
this.handleDidChangeTextDocument,
undefined,
this.disposables
)
// Listen for messages sent from the extensions webview.
webviewPanel.webview.onDidReceiveMessage(
this.handleMessageFromWebview,
undefined,
this.disposables
)
// Send the initial document content to bootstrap the Tldraw/Tldraw component.
webviewPanel.webview.postMessage({
type: 'openedFile',
text: document.getText(),
} as MessageFromExtension)
// Clean up disposables when the editor is closed.
webviewPanel.onDidDispose(this.handleDidDispose)
}
private handleDidDispose = () => {
this.disposables.forEach(({ dispose }) => dispose())
}
private handleDidSaveTextDocument = () => {
const { webviewPanel, document } = this
if (!(webviewPanel && document)) return
webviewPanel.webview.postMessage({
type: 'fileSaved',
text: document.getText(),
} as MessageFromExtension)
}
private handleDidChangeTextDocument = (event: vscode.TextDocumentChangeEvent) => {
// TODO
// If we can figure out whether the change came from inside of the
// editor vs. from some other app, we can update the document to
// show that external change.
}
private handleMessageFromWebview = (e: MessageFromWebview) => {
const { document } = this
if (!document) return
switch (e.type) {
case 'editorUpdated': {
// The event will contain the new TDFile as JSON.
const nextFile = JSON.parse(e.text) as TDFile
if (document.getText()) {
try {
// Parse the contents of the current document.
const currentFile = JSON.parse(document.getText()) as TDFile
// Ensure that the current file's pageStates are preserved
// in the next file, unless the associated pages have been deleted.
Object.values(currentFile.document.pageStates).forEach((pageState) => {
if (nextFile.document.pages[pageState.id] !== undefined) {
nextFile.document.pageStates[pageState.id] = pageState
}
})
} catch (e) {
console.error('Could not parse the current file to JSON.')
}
}
// Create an edit that replaces the document's current text
// content (a serialized TDFile) with the next file.
const edit = new vscode.WorkspaceEdit()
edit.replace(
document.uri,
new vscode.Range(0, 0, document.lineCount, 0),
JSON.stringify(nextFile, null, 2)
)
vscode.workspace.applyEdit(edit)
break
}
}
}
private getHtmlForWebview = (): string => {
const { document, context, webviewPanel } = this
let documentContent: string
let cssSrc: string | vscode.Uri
let jsSrc: string | vscode.Uri
const assetSrc = webviewPanel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, 'editor/', 'tldraw-assets.json')
)
try {
JSON.parse(document.getText())
documentContent = document.getText()
} catch (error) {
// For now we're going to tread badly formed .tldr files as freshly created files.
// This will happen if say a user creates a new .tldr file using New File or if they
// have a bad auto-merge that messes up the json of an existing .tldr file
// We pass null as the initialDocument value if we can't parse as json.
documentContent = 'null'
}
if (process.env.NODE_ENV === 'production') {
cssSrc = webviewPanel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, 'editor', 'index.css')
)
jsSrc = webviewPanel.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, 'editor', 'index.js')
)
} else {
const localhost = 'http://localhost:5420/'
cssSrc = `${localhost}index.css`
jsSrc = `${localhost}index.js`
}
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="${cssSrc}" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>tldraw</title>
</head>
<body>
<div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript>
<script>
var currentFile = ${documentContent};
var assetSrc = "${assetSrc}";
</script>
<script src="${jsSrc}"></script>
</body>
</html>
`
}
}

View file

@ -1,11 +0,0 @@
import * as vscode from 'vscode'
import { TldrawEditorProvider } from './TldrawEditorProvider'
// When a .tldr is first opened or created, activate the extension.
export function activate(context: vscode.ExtensionContext) {
try {
context.subscriptions.push(TldrawEditorProvider.register(context))
} catch (e) {
console.error(e)
}
}

View file

@ -1,14 +0,0 @@
export type MessageFromWebview = {
type: 'editorUpdated'
text: string
}
export type MessageFromExtension =
| {
type: 'openedFile'
text: string
}
| {
type: 'fileSaved'
text: string
}

View file

@ -1,8 +0,0 @@
export function getNonce() {
let text = ''
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}

View file

@ -1,20 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"outDir": "dist",
"lib": ["es6", "WebWorker"],
"sourceMap": true,
"rootDir": "src",
"strict": true,
"paths": {
"@tldraw/tldraw": ["../../../packages/tldraw"]
}
},
"references": [
{
"path": "../../../packages/tldraw"
}
],
"exclude": ["node_modules", ".vscode-test-web"]
}

File diff suppressed because it is too large Load diff

View file

@ -1,7 +0,0 @@
{
"root": true,
"extends": "next/core-web-vitals",
"rules": {
"@typescript-eslint/no-explicit-any": "off"
}
}

34
apps/www/.gitignore vendored
View file

@ -1,34 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# 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
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel

View file

@ -1,342 +0,0 @@
# @tldraw/www
## 1.8.3
### Patch Changes
- Include clipboard fixes.
- Updated dependencies
- @tldraw/core@1.23.2
- @tldraw/tldraw@1.29.2
## 1.8.2
### Patch Changes
- Fix clipboard stealing focus.
- Updated dependencies
- @tldraw/core@1.23.1
- @tldraw/tldraw@1.29.1
## 1.8.1
### Patch Changes
- Updated dependencies
- @tldraw/core@1.23.0
- @tldraw/tldraw@1.29.0
## 1.8.0
### Minor Changes
- - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates German translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
### Patch Changes
- Updated dependencies
- @tldraw/core@1.22.0
- @tldraw/tldraw@1.28.0
## 1.7.27
### Patch Changes
- - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates German translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
- 12c0b2ac: - Adds Galacian language translation
- Adds Farsi (Persian) language translation
- Updates Norwegian translation
- Updates Japanese translation
- Updates Spanish translation
- Improves aria-labels
- Fixes a bug with multiplayer menu
- Fixes a bug with image exports
- Updated dependencies
- Updated dependencies [12c0b2ac]
- @tldraw/core@1.21.1
- @tldraw/tldraw@1.27.1
## 1.7.26
### Patch Changes
- Updated dependencies
- @tldraw/core@1.21.0
- @tldraw/tldraw@1.27.0
## 1.7.25
### Patch Changes
- Updated dependencies
- @tldraw/core@1.20.3
- @tldraw/tldraw@1.26.4
## 1.7.24
### Patch Changes
- Updated dependencies
- @tldraw/core@1.20.2
- @tldraw/tldraw@1.26.3
## 1.7.23
### Patch Changes
- Updated dependencies
- @tldraw/core@1.20.1
- @tldraw/tldraw@1.26.2
## 1.7.22
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.26.1
## 1.7.21
### Patch Changes
- Updated dependencies
- @tldraw/core@1.20.0
- @tldraw/tldraw@1.26.0
## 1.7.20
### Patch Changes
- Updated dependencies
- @tldraw/core@1.19.0
- @tldraw/tldraw@1.25.0
## 1.7.19
### Patch Changes
- Updated dependencies
- @tldraw/core@1.18.4
- @tldraw/tldraw@1.24.5
## 1.7.18
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.24.4
## 1.7.17
### Patch Changes
- Small bump.
- Updated dependencies
- @tldraw/core@1.18.3
- @tldraw/tldraw@1.24.3
## 1.7.16
### Patch Changes
- Updated dependencies
- @tldraw/core@1.18.2
- @tldraw/tldraw@1.24.2
## 1.7.15
### Patch Changes
- Updated dependencies
- @tldraw/core@1.18.1
- @tldraw/tldraw@1.24.1
## 1.7.14
### Patch Changes
- Updated dependencies
- @tldraw/core@1.18.0
- @tldraw/tldraw@1.24.0
## 1.7.13
### Patch Changes
- Updated dependencies
- @tldraw/core@1.17.0
- @tldraw/tldraw@1.23.0
## 1.7.12
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.22.1
## 1.7.11
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.22.0
## 1.7.10
### Patch Changes
- Updated dependencies
- @tldraw/core@1.16.0
- @tldraw/tldraw@1.21.0
## 1.7.9
### Patch Changes
- Updated dependencies
- @tldraw/core@1.15.0
- @tldraw/tldraw@1.20.0
## 1.7.8
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.19.0
## 1.7.7
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.18.3
## 1.7.6
### Patch Changes
- Updated dependencies
- @tldraw/core@1.14.1
- @tldraw/tldraw@1.18.2
## 1.7.5
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.18.1
## 1.7.4
### Patch Changes
- Updated dependencies [8ef86c19]
- @tldraw/tldraw@1.18.0
## 1.7.3
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.17.2
## 1.7.2
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.17.1
## 1.7.1
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.17.0
## 1.7.0
### Minor Changes
- d919bd27: Bump dependencies, add international support.
### Patch Changes
- Updated dependencies [d919bd27]
- Updated dependencies
- @tldraw/core@1.14.0
- @tldraw/tldraw@1.16.0
## 1.7.0-next.0
### Minor Changes
- Bump dependencies, add international support.
### Patch Changes
- Updated dependencies
- @tldraw/core@1.14.0-next.0
- @tldraw/tldraw@1.16.0-next.0
## 1.6.7
### Patch Changes
- Updated dependencies
- @tldraw/core@1.13.1
- @tldraw/tldraw@1.15.1
## 1.6.6
### Patch Changes
- Updated dependencies
- @tldraw/core@1.13.0
- @tldraw/tldraw@1.15.0
## 1.6.5
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.14.2
## 1.6.4
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.14.1
## 1.6.3
### Patch Changes
- Updated dependencies
- @tldraw/tldraw@1.14.0
## 1.6.2
### Patch Changes
- Fix publish version.
- Updated dependencies
- @tldraw/core@1.9.1
- @tldraw/tldraw@1.9.1

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2022 Stephen Ruiz Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,7 +0,0 @@
<div style="text-align: center; transform: scale(.5);">
<img src="https://github.com/tldraw/tldraw/raw/main/assets/card-repo.png"/>
</div>
# @tldraw/www
The [tldraw](https://tldraw.com) website.

View file

@ -1,93 +0,0 @@
import { ExternalLinkIcon } from '@radix-ui/react-icons'
import React, { useLayoutEffect } from 'react'
import { css, styled } from '~styles'
const STORAGE_KEY = 'tldraw_dismiss_beta_notification_3'
export function BetaNotification() {
const [isDismissed, setIsDismissed] = React.useState(true)
useLayoutEffect(() => {
try {
const storageIsDismissed = localStorage.getItem(STORAGE_KEY)
if (storageIsDismissed !== null) {
return
} else {
setIsDismissed(false)
}
} catch (err) {
setIsDismissed(false)
}
}, [])
const handleDismiss = React.useCallback(() => {
setIsDismissed(true)
localStorage.setItem(STORAGE_KEY, 'true')
}, [])
if (isDismissed) return null
return (
<Panel>
<div>
On April 4th 2023 at 9:30AM UTC, tldraw will be offline as we upgrade to our new version.
</div>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginRight: -14,
marginLeft: -14,
marginBottom: -14,
}}
>
<Button onClick={handleDismiss}>Dismiss</Button>
<Link href="https://tldraw.substack.com/p/tldraws-upcoming-re-launch" target="_blank">
Learn more <ExternalLinkIcon style={{ marginLeft: 4, marginTop: 1, height: 14 }} />
</Link>
</div>
</Panel>
)
}
const Panel = styled('div', {
position: 'absolute',
top: 42,
left: 0,
margin: 16,
zIndex: 999,
backgroundColor: '$panel',
flexDirection: 'column',
boxShadow: '$panel',
padding: 16,
fontSize: 'var(--fontSizes-2)',
fontFamily: 'var(--fonts-ui)',
width: 300,
display: 'flex',
gap: 8,
border: '1px solid $panelContrast',
overflow: 'hidden',
borderRadius: 9,
})
const buttonStyles = css({
borderRadius: '$2',
backgroundColor: '$panel',
padding: '0 14px',
height: 40,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'inherit',
font: 'inherit',
cursor: 'pointer',
border: 'none',
'&:hover': {
backgroundColor: '$hover',
},
})
const Button = styled('button', buttonStyles)
const Link = styled('a', buttonStyles)

View file

@ -1,48 +0,0 @@
import { Tldraw, TldrawApp, TldrawProps, useFileSystem } from '@tldraw/tldraw'
import * as React from 'react'
import { useUploadAssets } from '~hooks/useUploadAssets'
import * as gtag from '~utils/gtag'
import { BetaNotification } from './BetaNotification'
declare const window: Window & { app: TldrawApp }
interface EditorProps {
id?: string
}
const Editor = ({ id = 'home', ...rest }: EditorProps & Partial<TldrawProps>) => {
const handleMount = React.useCallback((app: TldrawApp) => {
window.app = app
}, [])
// Send events to gtag as actions.
const handlePersist = React.useCallback((_app: TldrawApp, reason?: string) => {
gtag.event({
action: reason ?? '',
category: 'editor',
label: reason ?? 'persist',
value: 0,
})
}, [])
const fileSystemEvents = useFileSystem()
const { onAssetUpload } = useUploadAssets()
return (
<div className="tldraw">
<Tldraw
id={id}
autofocus
onMount={handleMount}
onPersist={handlePersist}
onAssetUpload={onAssetUpload}
{...fileSystemEvents}
{...rest}
/>
<BetaNotification />
</div>
)
}
export default Editor

View file

@ -1,126 +0,0 @@
import React from 'react'
import { styled } from '~styles'
export default function IFrameWarning({ url = 'https://tldraw.com' }: { url?: string }) {
const [copied, setCopied] = React.useState(false)
const rTimeout = React.useRef<any>(0)
const handleCopy = React.useCallback(() => {
setCopied(true)
clearTimeout(rTimeout.current)
rTimeout.current = setTimeout(() => {
setCopied(false)
}, 1200)
const textarea = document.createElement('textarea')
textarea.setAttribute('position', 'fixed')
textarea.setAttribute('top', '0')
textarea.setAttribute('readonly', 'true')
textarea.setAttribute('contenteditable', 'true')
textarea.style.position = 'fixed'
textarea.value = url
document.body.appendChild(textarea)
textarea.focus()
textarea.select()
try {
const range = document.createRange()
range.selectNodeContents(textarea)
const sel = window.getSelection()
if (sel) {
sel.removeAllRanges()
sel.addRange(range)
textarea.setSelectionRange(0, textarea.value.length)
}
document.execCommand('copy')
} catch (err) {
null // Could not copy to clipboard
} finally {
document.body.removeChild(textarea)
}
}, [url])
return (
<StyledContainer>
<StyledUrlLink href={url} target="_parent">
Visit this page on tldraw.com{' '}
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3 2C2.44772 2 2 2.44772 2 3V12C2 12.5523 2.44772 13 3 13H12C12.5523 13 13 12.5523 13 12V8.5C13 8.22386 12.7761 8 12.5 8C12.2239 8 12 8.22386 12 8.5V12H3V3L6.5 3C6.77614 3 7 2.77614 7 2.5C7 2.22386 6.77614 2 6.5 2H3ZM12.8536 2.14645C12.9015 2.19439 12.9377 2.24964 12.9621 2.30861C12.9861 2.36669 12.9996 2.4303 13 2.497L13 2.5V2.50049V5.5C13 5.77614 12.7761 6 12.5 6C12.2239 6 12 5.77614 12 5.5V3.70711L6.85355 8.85355C6.65829 9.04882 6.34171 9.04882 6.14645 8.85355C5.95118 8.65829 5.95118 8.34171 6.14645 8.14645L11.2929 3H9.5C9.22386 3 9 2.77614 9 2.5C9 2.22386 9.22386 2 9.5 2H12.4999H12.5C12.5678 2 12.6324 2.01349 12.6914 2.03794C12.7504 2.06234 12.8056 2.09851 12.8536 2.14645Z"
fill="currentColor"
stroke="black"
strokeWidth=".5"
></path>
</svg>
</StyledUrlLink>
<StyledUrlContainer onClick={handleCopy}>
<span>{url}</span>
<svg
width="18"
height="18"
viewBox="0 0 15 15"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
{copied ? (
<path d="M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z" />
) : (
<path d="M5 2V1H10V2H5ZM4.75 0C4.33579 0 4 0.335786 4 0.75V1H3.5C2.67157 1 2 1.67157 2 2.5V12.5C2 13.3284 2.67157 14 3.5 14H7V13H3.5C3.22386 13 3 12.7761 3 12.5V2.5C3 2.22386 3.22386 2 3.5 2H4V2.25C4 2.66421 4.33579 3 4.75 3H10.25C10.6642 3 11 2.66421 11 2.25V2H11.5C11.7761 2 12 2.22386 12 2.5V7H13V2.5C13 1.67157 12.3284 1 11.5 1H11V0.75C11 0.335786 10.6642 0 10.25 0H4.75ZM9 8.5C9 8.77614 8.77614 9 8.5 9C8.22386 9 8 8.77614 8 8.5C8 8.22386 8.22386 8 8.5 8C8.77614 8 9 8.22386 9 8.5ZM10.5 9C10.7761 9 11 8.77614 11 8.5C11 8.22386 10.7761 8 10.5 8C10.2239 8 10 8.22386 10 8.5C10 8.77614 10.2239 9 10.5 9ZM13 8.5C13 8.77614 12.7761 9 12.5 9C12.2239 9 12 8.77614 12 8.5C12 8.22386 12.2239 8 12.5 8C12.7761 8 13 8.22386 13 8.5ZM14.5 9C14.7761 9 15 8.77614 15 8.5C15 8.22386 14.7761 8 14.5 8C14.2239 8 14 8.22386 14 8.5C14 8.77614 14.2239 9 14.5 9ZM15 10.5C15 10.7761 14.7761 11 14.5 11C14.2239 11 14 10.7761 14 10.5C14 10.2239 14.2239 10 14.5 10C14.7761 10 15 10.2239 15 10.5ZM14.5 13C14.7761 13 15 12.7761 15 12.5C15 12.2239 14.7761 12 14.5 12C14.2239 12 14 12.2239 14 12.5C14 12.7761 14.2239 13 14.5 13ZM14.5 15C14.7761 15 15 14.7761 15 14.5C15 14.2239 14.7761 14 14.5 14C14.2239 14 14 14.2239 14 14.5C14 14.7761 14.2239 15 14.5 15ZM8.5 11C8.77614 11 9 10.7761 9 10.5C9 10.2239 8.77614 10 8.5 10C8.22386 10 8 10.2239 8 10.5C8 10.7761 8.22386 11 8.5 11ZM9 12.5C9 12.7761 8.77614 13 8.5 13C8.22386 13 8 12.7761 8 12.5C8 12.2239 8.22386 12 8.5 12C8.77614 12 9 12.2239 9 12.5ZM8.5 15C8.77614 15 9 14.7761 9 14.5C9 14.2239 8.77614 14 8.5 14C8.22386 14 8 14.2239 8 14.5C8 14.7761 8.22386 15 8.5 15ZM11 14.5C11 14.7761 10.7761 15 10.5 15C10.2239 15 10 14.7761 10 14.5C10 14.2239 10.2239 14 10.5 14C10.7761 14 11 14.2239 11 14.5ZM12.5 15C12.7761 15 13 14.7761 13 14.5C13 14.2239 12.7761 14 12.5 14C12.2239 14 12 14.2239 12 14.5C12 14.7761 12.2239 15 12.5 15Z" />
)}
</svg>
</StyledUrlContainer>
</StyledContainer>
)
}
const StyledContainer = styled('div', {
position: 'absolute',
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontFamily: '$body',
fontWeight: 'normal',
fontSize: '$3',
gap: '$5',
flexDirection: 'column',
border: '1px solid $hover',
borderRadius: '$2',
})
const StyledUrlLink = styled('a', {
display: 'flex',
alignItems: 'center',
gap: '$2',
padding: '$5',
})
const StyledUrlContainer = styled('a', {
backgroundColor: '$hover',
borderRadius: '$2',
maxWidth: '62%',
minWidth: 320,
gap: '$4',
padding: '$4 $5',
fontSize: '$2',
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
'& span': {
flexGrow: 2,
overflow: 'auto',
whiteSpace: 'nowrap',
'-ms-overflow-style': 'none' /* for Internet Explorer, Edge */,
scrollbarWidth: 'none',
'&::webkit-scrollbar': {
display: 'none',
},
},
})

View file

@ -1,108 +0,0 @@
import { ReactNode, useEffect, useRef, useState } from 'react'
import { light, styled } from '~styles'
const CONTROL_SERVER = process.env.NEXT_PUBLIC_CONTROL_SERVER
? process.env.NEXT_PUBLIC_CONTROL_SERVER
: process.env.NEXT_PUBLIC_ENABLE_DEV_CONTROL_SERVER
? 'http://localhost:3001'
: null
type MaintenanceModeConfig =
| {
enabled: false
ttlSeconds: number
}
| {
enabled: true
ttlSeconds: number
titleMessage: string
bodyMessageHtml: string
}
type ControlResponse = {
maintenance: MaintenanceModeConfig
}
export function MaintenanceMode({ children }: { children: ReactNode }) {
const [maintenanceMode, setMaintenanceMode] = useState<MaintenanceModeConfig | null>(null)
useEffect(() => {
if (!CONTROL_SERVER) return
let isCancelled = false
const updateMaintenanceMode = async () => {
try {
const response = await fetch(`${CONTROL_SERVER}/control.json`)
const data: ControlResponse = await response.json()
if (isCancelled) return
setMaintenanceMode(data.maintenance)
} catch {
setMaintenanceMode({
enabled: false,
ttlSeconds: 60,
})
}
}
if (maintenanceMode) {
const refreshTimeout = setTimeout(updateMaintenanceMode, maintenanceMode.ttlSeconds * 1000)
return () => {
isCancelled = true
clearTimeout(refreshTimeout)
}
} else {
updateMaintenanceMode()
return () => {
isCancelled = true
}
}
}, [maintenanceMode])
const isMaintenanceModeEnabled = maintenanceMode?.enabled ?? false
const wasInMaintenanceModeRef = useRef(isMaintenanceModeEnabled)
useEffect(() => {
// If we were in maintenance mode and now we're not, reload the page
if (wasInMaintenanceModeRef.current && !isMaintenanceModeEnabled) {
window.location.reload()
}
wasInMaintenanceModeRef.current = isMaintenanceModeEnabled
}, [isMaintenanceModeEnabled])
if (maintenanceMode?.enabled) {
return (
<div className={`tldraw ${light}`}>
<Container>
<Modal>
<Heading>{maintenanceMode.titleMessage}</Heading>
<div dangerouslySetInnerHTML={{ __html: maintenanceMode.bodyMessageHtml }} />
</Modal>
</Container>
</div>
)
}
return <>{children}</>
}
const Container = styled('div', {
backgroundColor: '$canvas',
position: 'absolute',
inset: 0,
padding: '1rem',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
})
const Modal = styled('div', {
backgroundColor: '$panel',
padding: '1rem 1.5rem',
borderRadius: '$2',
boxShadow: '$8',
maxWidth: '400px',
width: '100%',
})
const Heading = styled('h2', {
margin: 0,
marginTop: '1rem',
})

View file

@ -1,73 +0,0 @@
import { TDUserStatus, Tldraw, TldrawProps, useFileSystem } from '@tldraw/tldraw'
import * as React from 'react'
import { useMultiplayerAssets } from '~hooks/useMultiplayerAssets'
import { useMultiplayerState } from '~hooks/useMultiplayerState'
import { useUploadAssets } from '~hooks/useUploadAssets'
import { styled } from '~styles'
import { RoomProvider } from '~utils/liveblocks'
import { BetaNotification } from './BetaNotification'
interface Props {
roomId: string
}
const MultiplayerEditor = ({ roomId }: Props) => {
return (
<RoomProvider
id={roomId}
initialPresence={{
id: 'DEFAULT_ID',
user: {
id: 'DEFAULT_ID',
status: TDUserStatus.Connecting,
activeShapes: [],
color: 'black',
point: [0, 0],
selectedIds: [],
},
}}
>
<Editor roomId={roomId} />
</RoomProvider>
)
}
// Inner Editor
function Editor({ roomId }: Props) {
const fileSystemEvents = useFileSystem()
const { error, ...events } = useMultiplayerState(roomId)
const { onAssetCreate, onAssetDelete } = useMultiplayerAssets()
const { onAssetUpload } = useUploadAssets()
if (error) return <LoadingScreen>Error: {error.message}</LoadingScreen>
return (
<div className="tldraw">
<Tldraw
autofocus
disableAssets={false}
showPages={false}
onAssetCreate={onAssetCreate}
onAssetDelete={onAssetDelete}
onAssetUpload={onAssetUpload}
{...fileSystemEvents}
{...events}
/>
<BetaNotification />
</div>
)
}
export default MultiplayerEditor
const LoadingScreen = styled('div', {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
})

View file

@ -1,66 +0,0 @@
import { TDUserStatus, Tldraw, useFileSystem } from '@tldraw/tldraw'
import * as React from 'react'
import { useReadOnlyMultiplayerState } from '~hooks/useReadOnlyMultiplayerState'
import { styled } from '~styles'
import { RoomProvider } from '~utils/liveblocks'
interface Props {
roomId: string
}
const ReadOnlyMultiplayerEditor = ({ roomId }: Props) => {
return (
<RoomProvider
id={roomId}
initialPresence={{
id: 'DEFAULT_ID',
user: {
id: 'DEFAULT_ID',
status: TDUserStatus.Connecting,
activeShapes: [],
color: 'black',
point: [0, 0],
selectedIds: [],
},
}}
>
<ReadOnlyEditor roomId={roomId} />
</RoomProvider>
)
}
// Inner Editor
function ReadOnlyEditor({ roomId }: Props) {
const { onSaveProjectAs, onSaveProject } = useFileSystem()
const { error, ...events } = useReadOnlyMultiplayerState(roomId)
if (error) return <LoadingScreen>Error: {error.message}</LoadingScreen>
return (
<div className="tldraw">
<Tldraw
autofocus
disableAssets={false}
showPages={false}
onSaveProjectAs={onSaveProjectAs}
onSaveProject={onSaveProject}
readOnly
{...events}
/>
</div>
)
}
export default ReadOnlyMultiplayerEditor
const LoadingScreen = styled('div', {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
})

View file

@ -1,42 +0,0 @@
import { Utils } from '@tldraw/core'
import { TDAsset, TldrawApp } from '@tldraw/tldraw'
import { useCallback } from 'react'
export function useMultiplayerAssets() {
const onAssetCreate = useCallback(
// Send the asset to our upload endpoint, which in turn will send it to AWS and
// respond with the URL of the uploaded file.
async (app: TldrawApp, file: File, id: string): Promise<string | false> => {
const filename = encodeURIComponent((id ?? Utils.uniqueId()) + file.name)
const fileType = encodeURIComponent(file.type)
const res = await fetch(`/api/upload?file=${filename}&fileType=${fileType}`)
const { url, fields } = await res.json()
const formData = new FormData()
Object.entries({ ...fields, file }).forEach(([key, value]) => {
formData.append(key, value as any)
})
const upload = await fetch(url, {
method: 'POST',
body: formData,
})
if (!upload.ok) return false
return url + '/' + filename
},
[]
)
const onAssetDelete = useCallback(async (app: TldrawApp, id: string): Promise<boolean> => {
// noop
return true
}, [])
return { onAssetCreate, onAssetDelete }
}

View file

@ -1,260 +0,0 @@
import { LiveMap } from '@liveblocks/client'
import type { TDAsset, TDBinding, TDShape, TDUser, TldrawApp } from '@tldraw/tldraw'
import React, { useCallback, useRef, useState } from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { Storage, useRedo, useRoom, useUndo, useUpdateMyPresence } from '~utils/liveblocks'
declare const window: Window & { app: TldrawApp }
export function useMultiplayerState(roomId: string) {
const [app, setApp] = useState<TldrawApp>()
const [error, setError] = useState<Error>()
const [loading, setLoading] = useState(true)
const room = useRoom()
const onUndo = useUndo()
const onRedo = useRedo()
const updateMyPresence = useUpdateMyPresence()
const rIsPaused = useRef(false)
const rLiveShapes = useRef<Storage['shapes']>()
const rLiveBindings = useRef<Storage['bindings']>()
const rLiveAssets = useRef<Storage['assets']>()
// Callbacks --------------
// Put the state into the window, for debugging.
const onMount = useCallback(
(app: TldrawApp) => {
app.loadRoom(roomId)
app.pause() // Turn off the app's own undo / redo stack
window.app = app
setApp(app)
},
[roomId]
)
// Update the live shapes when the app's shapes change.
const onChangePage = useCallback(
(
app: TldrawApp,
shapes: Record<string, TDShape | undefined>,
bindings: Record<string, TDBinding | undefined>,
assets: Record<string, TDAsset | undefined>
) => {
room.batch(() => {
const lShapes = rLiveShapes.current
const lBindings = rLiveBindings.current
const lAssets = rLiveAssets.current
if (!(lShapes && lBindings && lAssets)) return
Object.entries(shapes).forEach(([id, shape]) => {
if (!shape) {
lShapes.delete(id)
} else {
lShapes.set(shape.id, shape)
}
})
Object.entries(bindings).forEach(([id, binding]) => {
if (!binding) {
lBindings.delete(id)
} else {
lBindings.set(binding.id, binding)
}
})
Object.entries(assets).forEach(([id, asset]) => {
if (!asset) {
lAssets.delete(id)
} else {
lAssets.set(asset.id, asset)
}
})
})
},
[room]
)
// Handle presence updates when the user's pointer / selection changes
const onChangePresence = useCallback(
(app: TldrawApp, user: TDUser) => {
updateMyPresence({ id: app.room?.userId, user })
},
[updateMyPresence]
)
// Document Changes --------
React.useEffect(() => {
const unsubs: (() => void)[] = []
if (!(app && room)) return
// Handle errors
unsubs.push(room.subscribe('error', (error) => setError(error)))
// Handle changes to other users' presence
unsubs.push(
room.subscribe('others', (others, event) => {
if (event.type === 'leave') {
if (event.user.presence) {
app?.removeUser(event.user.presence.id)
}
} else {
app.updateUsers(
others
.toArray()
.filter((other) => other.presence)
.map((other) => other.presence!.user)
.filter(Boolean)
)
}
})
)
let stillAlive = true
// Setup the document's storage and subscriptions
async function setupDocument() {
const storage = await room.getStorage()
// Migrate previous versions
const version = storage.root.get('version')
// Initialize (get or create) maps for shapes/bindings/assets
let lShapes = storage.root.get('shapes')
if (!lShapes || !('_serialize' in lShapes)) {
storage.root.set('shapes', new LiveMap())
lShapes = storage.root.get('shapes')
}
rLiveShapes.current = lShapes
let lBindings = storage.root.get('bindings')
if (!lBindings || !('_serialize' in lBindings)) {
storage.root.set('bindings', new LiveMap())
lBindings = storage.root.get('bindings')
}
rLiveBindings.current = lBindings
let lAssets = storage.root.get('assets')
if (!lAssets || !('_serialize' in lAssets)) {
storage.root.set('assets', new LiveMap())
lAssets = storage.root.get('assets')
}
rLiveAssets.current = lAssets
if (!version) {
// The doc object will only be present if the document was created
// prior to the current multiplayer implementation. At this time, the
// document was a single LiveObject named 'doc'. If we find a doc,
// then we need to move the shapes and bindings over to the new structures
// and then mark the doc as migrated.
const doc = storage.root.get('doc')
// No doc? No problem. This was likely a newer document
if (doc) {
const {
document: {
pages: {
page: { shapes, bindings },
},
assets,
},
} = doc.toObject()
Object.values(shapes).forEach((shape) => lShapes.set(shape.id, shape))
Object.values(bindings).forEach((binding) => lBindings.set(binding.id, binding))
Object.values(assets).forEach((asset) => lAssets.set(asset.id, asset))
}
}
// Save the version number for future migrations
storage.root.set('version', 2.1)
// Subscribe to changes
const handleChanges = () => {
app?.replacePageContent(
Object.fromEntries(lShapes.entries()),
Object.fromEntries(lBindings.entries()),
Object.fromEntries(lAssets.entries())
)
}
if (stillAlive) {
unsubs.push(room.subscribe(lShapes, handleChanges))
// Update the document with initial content
handleChanges()
// Zoom to fit the content
app.zoomToFit()
if (app.zoom > 1) {
app.resetZoom()
}
setLoading(false)
}
}
setupDocument()
return () => {
stillAlive = false
unsubs.forEach((unsub) => unsub())
}
}, [room, app])
const onSessionStart = React.useCallback(() => {
if (!room) return
room.history.pause()
rIsPaused.current = true
}, [room])
const onSessionEnd = React.useCallback(() => {
if (!room) return
room.history.resume()
rIsPaused.current = false
}, [room])
useHotkeys(
'ctrl+shift+l;,⌘+shift+l',
() => {
if (window.confirm('Reset the document?')) {
room.batch(() => {
const lShapes = rLiveShapes.current
const lBindings = rLiveBindings.current
const lAssets = rLiveAssets.current
if (!(lShapes && lBindings && lAssets)) return
lShapes.forEach((shape) => {
lShapes.delete(shape.id)
})
lBindings.forEach((shape) => {
lBindings.delete(shape.id)
})
lAssets.forEach((shape) => {
lAssets.delete(shape.id)
})
})
}
},
[]
)
return {
onUndo,
onRedo,
onMount,
onSessionStart,
onSessionEnd,
onChangePage,
onChangePresence,
error,
loading,
}
}

View file

@ -1,148 +0,0 @@
import { LiveMap } from '@liveblocks/client'
import type { TDUser, TldrawApp } from '@tldraw/tldraw'
import React, { useCallback, useRef, useState } from 'react'
import { Storage, useRedo, useRoom, useUndo, useUpdateMyPresence } from '~utils/liveblocks'
declare const window: Window & { app: TldrawApp }
export function useReadOnlyMultiplayerState(roomId: string) {
const [app, setApp] = useState<TldrawApp>()
const [error, setError] = useState<Error>()
const [loading, setLoading] = useState(true)
const room = useRoom()
const onUndo = useUndo()
const onRedo = useRedo()
const updateMyPresence = useUpdateMyPresence()
const rIsPaused = useRef(false)
const rLiveShapes = useRef<Storage['shapes']>()
const rLiveBindings = useRef<Storage['bindings']>()
const rLiveAssets = useRef<Storage['assets']>()
// Callbacks --------------
// Put the state into the window, for debugging.
const onMount = useCallback(
(app: TldrawApp) => {
app.loadRoom(roomId)
app.pause() // Turn off the app's own undo / redo stack
window.app = app
setApp(app)
},
[roomId]
)
// Handle presence updates when the user's pointer / selection changes
const onChangePresence = useCallback(
(app: TldrawApp, user: TDUser) => {
updateMyPresence({ id: app.room?.userId, user })
},
[updateMyPresence]
)
// Document Changes --------
React.useEffect(() => {
const unsubs: (() => void)[] = []
if (!(app && room)) return
// Handle errors
unsubs.push(room.subscribe('error', (error) => setError(error)))
// Handle changes to other users' presence
unsubs.push(
room.subscribe('others', (others, event) => {
if (event.type === 'leave') {
if (event.user.presence) {
app?.removeUser(event.user.presence.id)
}
} else {
app.updateUsers(
others
.toArray()
.filter((other) => other.presence)
.map((other) => other.presence!.user)
.filter(Boolean)
)
}
})
)
let stillAlive = true
// Setup the document's storage and subscriptions
async function setupDocument() {
const storage = await room.getStorage()
// Migrate previous versions
const version = storage.root.get('version')
// Initialize (get or create) maps for shapes/bindings/assets
let lShapes = storage.root.get('shapes')
if (!lShapes || !('_serialize' in lShapes)) {
storage.root.set('shapes', new LiveMap())
lShapes = storage.root.get('shapes')
}
rLiveShapes.current = lShapes
let lBindings = storage.root.get('bindings')
if (!lBindings || !('_serialize' in lBindings)) {
storage.root.set('bindings', new LiveMap())
lBindings = storage.root.get('bindings')
}
rLiveBindings.current = lBindings
let lAssets = storage.root.get('assets')
if (!lAssets || !('_serialize' in lAssets)) {
storage.root.set('assets', new LiveMap())
lAssets = storage.root.get('assets')
}
rLiveAssets.current = lAssets
// Save the version number for future migrations
storage.root.set('version', 2.1)
// Subscribe to changes
const handleChanges = () => {
app?.replacePageContent(
Object.fromEntries(lShapes.entries()),
Object.fromEntries(lBindings.entries()),
Object.fromEntries(lAssets.entries())
)
}
if (stillAlive) {
unsubs.push(room.subscribe(lShapes, handleChanges))
// Update the document with initial content
handleChanges()
// Zoom to fit the content
app.zoomToFit()
if (app.zoom > 1) {
app.resetZoom()
}
setLoading(false)
}
}
setupDocument()
return () => {
stillAlive = false
unsubs.forEach((unsub) => unsub())
}
}, [room, app])
return {
onUndo,
onRedo,
onMount,
onChangePresence,
error,
loading,
}
}

View file

@ -1,38 +0,0 @@
import { Utils } from '@tldraw/core'
import { TldrawApp } from '@tldraw/tldraw'
import { useCallback } from 'react'
export function useUploadAssets() {
const onAssetUpload = useCallback(
// Send the asset to our upload endpoint, which in turn will send it to AWS and
// respond with the URL of the uploaded file.
async (app: TldrawApp, file: File, id: string): Promise<string | false> => {
const filename = encodeURIComponent((id ?? Utils.uniqueId()) + file.name)
const fileType = encodeURIComponent(file.type)
const res = await fetch(`/api/upload?file=${filename}&fileType=${fileType}`)
const { url, fields } = await res.json()
const formData = new FormData()
Object.entries({ ...fields, file }).forEach(([key, value]) => {
formData.append(key, value as any)
})
const upload = await fetch(url, {
method: 'POST',
body: formData,
})
if (!upload.ok) return false
return url + '/' + filename
},
[]
)
return { onAssetUpload }
}

View file

@ -1,5 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View file

@ -1,24 +0,0 @@
const withPWA = require('next-pwa')
const withTM = require('next-transpile-modules')
const { GITHUB_ID, GITHUB_API_SECRET, NODE_ENV, VERCEL_GIT_COMMIT_SHA, GA_MEASUREMENT_ID } =
process.env
const isProduction = NODE_ENV === 'production'
module.exports = withTM(['@tldraw/tldraw', '@tldraw/core'])(
withPWA({
reactStrictMode: true,
pwa: {
disable: !isProduction,
dest: 'public',
},
productionBrowserSourceMaps: true,
env: {
NEXT_PUBLIC_COMMIT_SHA: VERCEL_GIT_COMMIT_SHA,
GA_MEASUREMENT_ID,
GITHUB_ID,
GITHUB_API_SECRET,
},
})
)

View file

@ -1,44 +0,0 @@
{
"name": "@tldraw/www",
"version": "1.8.3",
"private": true,
"description": "A tiny little drawing app (site).",
"repository": {
"type": "git",
"url": "git+https://github.com/tldraw/tldraw.git"
},
"license": "MIT",
"author": "@steveruizok",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "TIMING=1 next lint",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
},
"dependencies": {
"@liveblocks/client": "^0.18.3",
"@liveblocks/react": "^0.18.3",
"@stitches/react": "^1.2.8",
"@tldraw/core": "*",
"@tldraw/tldraw": "*",
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"aws-sdk": "^2.1053.0",
"eslint": "^8.8.0",
"eslint-config-next": "^12.0.10",
"lz-string": "^1.4.4",
"nanoid": "^3.3.4",
"next": "^12.1.6",
"next-pwa": "^5.5.4",
"next-themes": "^0.0.15",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hotkeys-hook": "^3.4.6",
"typescript": "^4.7.3"
},
"gitHead": "838fabdbff1a66d4d7ee8aa5c5d117bc55acbff2",
"devDependencies": {
"next-transpile-modules": "^9.0.0"
}
}

View file

@ -1,61 +0,0 @@
import '@fontsource/recursive'
import Head from 'next/head'
import type React from 'react'
import { MaintenanceMode } from '~components/MaintenanceMode'
import '~styles/globals.css'
import useGtag from '~utils/useGtag'
const APP_NAME = 'tldraw'
const APP_DESCRIPTION = 'A tiny little drawing app.'
const APP_URL = 'https://tldraw.com'
const IMAGE = 'https://tldraw.com/social-image.png'
function MyApp({ Component, pageProps }: any) {
useGtag()
return (
<>
<Head>
<meta name="application-name" content={APP_NAME} />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content={APP_NAME} />
<meta name="description" content={APP_DESCRIPTION} />
<meta name="format-detection" content="telephone=no" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="theme-color" content="#fafafa" />
<meta name="twitter:url" content={APP_URL} />
<meta name="twitter:title" content={APP_NAME} />
<meta name="twitter:description" content={APP_DESCRIPTION} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content="@tldraw" />
<meta name="twitter:site" content="@tldraw" />
<meta name="twitter:image" content={IMAGE} />
<meta property="og:type" content="website" />
<meta property="og:title" content={APP_NAME} />
<meta property="og:description" content={APP_DESCRIPTION} />
<meta property="og:site_name" content={APP_NAME} />
<meta property="og:url" content={APP_URL} />
<meta property="og:image" content={IMAGE} />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no"
/>
<link rel="manifest" href="/manifest.json" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" />
<title>tldraw</title>
</Head>
<MaintenanceMode>
<Component {...pageProps} />
</MaintenanceMode>
</>
)
}
export default MyApp

View file

@ -1,47 +0,0 @@
import NextDocument, { DocumentContext, Head, Html, Main, NextScript } from 'next/document'
import { getCssText } from '~styles'
import { GA_TRACKING_ID } from '~utils/gtag'
class MyDocument extends NextDocument {
static async getInitialProps(ctx: DocumentContext): Promise<any> {
const initialProps = await NextDocument.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
<style id="stitches" dangerouslySetInnerHTML={{ __html: getCssText() }} />
</>
),
}
}
render() {
return (
<Html lang="en">
<Head>
<script async src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`} />
<script
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}', {
page_path: window.location.pathname,
});
`,
}}
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument

View file

@ -1,72 +0,0 @@
import { Utils } from '@tldraw/core'
import { TDDocument } from '@tldraw/tldraw'
import { NextApiRequest, NextApiResponse } from 'next'
type RequestBody = {
pageId: string
document: TDDocument
}
export default async function CreateMultiplayerRoom(req: NextApiRequest, res: NextApiResponse) {
try {
// 1. Get an authentication token from Liveblocks
const { token } = await fetch('https://liveblocks.io/api/authorize', {
headers: {
Authorization: `Bearer ${process.env.LIVEBLOCKS_SECRET_KEY}`,
'Content-Type': 'application/json',
},
}).then((d) => d.json())
// 2. Create the Liveblocks storage JSON
const { pageId, document } = JSON.parse(req.body) as RequestBody
const storageJson = {
liveblocksType: 'LiveObject',
data: {
version: 2.1,
shapes: {
liveblocksType: 'LiveMap',
data: {},
},
bindings: {
liveblocksType: 'LiveMap',
data: {},
},
assets: {
liveblocksType: 'LiveMap',
data: {},
},
},
}
const page = document.pages[pageId]
storageJson.data.shapes.data = page.shapes ?? {}
storageJson.data.bindings.data = page.bindings ?? {}
storageJson.data.assets.data = document.assets ?? {}
// 3. Post the JSON and token to Liveblocks
const roomId = Utils.uniqueId()
const result = await fetch(`https://liveblocks.net/api/v1/room/${roomId}/storage`, {
method: 'POST',
body: JSON.stringify(storageJson),
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
})
if (result.status === 200) {
// If success, send back the url for the new multiplayer project
res.send({ status: 'success', message: result.statusText, url: '/r/' + roomId })
} else {
throw Error(result.statusText)
}
} catch (e) {
res.send({ status: 'error', message: e.message })
}
}

View file

@ -1,26 +0,0 @@
import aws from 'aws-sdk'
export default async function handler(req, res) {
aws.config.update({
accessKeyId: process.env.TL_AWS_ACCESS_KEY,
secretAccessKey: process.env.TL_AWS_SECRET_KEY,
region: process.env.TL_AWS_REGION,
signatureVersion: 'v4',
})
const s3 = new aws.S3()
const post = s3.createPresignedPost({
Bucket: process.env.TL_AWS_BUCKET_NAME,
Fields: {
key: req.query.file,
'Content-Type': req.query.fileType,
},
Expires: 60, // seconds
Conditions: [
['content-length-range', 0, 5242880], // up to 5 MB
],
})
res.status(200).json(post)
}

View file

@ -1,22 +0,0 @@
import dynamic from 'next/dynamic'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useMemo } from 'react'
const Editor = dynamic(() => import('~components/Editor'), { ssr: false }) as any
const Home = () => {
const { query } = useRouter()
const isExportMode = useMemo(() => 'exportMode' in query, [query])
return (
<>
<Head>
<title>tldraw</title>
</Head>
<Editor id="home" showUI={!isExportMode} />
</>
)
}
export default Home

View file

@ -1,41 +0,0 @@
import type { GetServerSideProps } from 'next'
import dynamic from 'next/dynamic'
import Head from 'next/head'
import * as React from 'react'
const IFrameWarning = dynamic(() => import('~components/IFrameWarning'), {
ssr: false,
}) as any
const MultiplayerEditor = dynamic(() => import('~components/MultiplayerEditor'), {
ssr: false,
}) as any
interface RoomProps {
id: string
}
export default function Room({ id }: RoomProps) {
if (typeof window !== 'undefined' && window.self !== window.top) {
return <IFrameWarning url={`${window.location.origin}/r/${id}`} />
}
return (
<>
<Head>
<title>tldraw - {id}</title>
</Head>
<MultiplayerEditor roomId={id} />
</>
)
}
export const getServerSideProps: GetServerSideProps = async (context) => {
const id = context.query.id?.toString()
return {
props: {
id,
},
}
}

View file

@ -1,27 +0,0 @@
import type { GetServerSideProps } from 'next'
import Head from 'next/head'
import * as React from 'react'
export default function RandomRoomPage() {
return (
<>
<Head>
<title>tldraw</title>
</Head>
</>
)
}
export const getServerSideProps: GetServerSideProps = async (context) => {
// Generate random id
const id = Date.now().toString()
// Route to a room with that id
context.res.setHeader('Location', `/r/${id}`)
context.res.statusCode = 307
// Return id (though it shouldn't matter)
return {
props: {},
}
}

View file

@ -1,42 +0,0 @@
import { Utils } from '@tldraw/core'
import type { GetServerSideProps } from 'next'
import dynamic from 'next/dynamic'
import Head from 'next/head'
import * as React from 'react'
const IFrameWarning = dynamic(() => import('~components/IFrameWarning'), {
ssr: false,
}) as any
const ReadOnlyMultiplayerEditor = dynamic(() => import('~components/ReadOnlyMultiplayerEditor'), {
ssr: false,
}) as any
interface RoomProps {
id: string
}
export default function Room({ id }: RoomProps) {
if (typeof window !== 'undefined' && window.self !== window.top) {
return <IFrameWarning url={`https://tldraw.com/v/${id}`} />
}
return (
<>
<Head>
<title>tldraw - {id} (read only)</title>
</Head>
<ReadOnlyMultiplayerEditor roomId={id} />
</>
)
}
export const getServerSideProps: GetServerSideProps = async (context) => {
const id = context.query.id?.toString()
return {
props: {
id: Utils.lns(id),
},
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

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