Welcome to the AppFlowy Web Project, a robust and versatile platform designed to bring the innovative features of
-AppFlowy to the web. This project uniquely supports running as a desktop application via Tauri, and offers web
-interfaces powered by WebAssembly (WASM). Dive into an exceptional development experience with high performance and
-extensive capabilities.
-
+
+
+
+
+
-## ๐ Features
+## ๐ Introduction
-- **Cross-Platform Compatibility**: Seamlessly run on desktop environments with Tauri, and on any web browser through
- WASM.
-- **High Performance**: Leverage the speed and efficiency of WebAssembly for your web interfaces.
-- **Tauri Integration**: Build lightweight, secure, and efficient desktop applications.
-- **Flexible Development**: Utilize a wide range of AppFlowy's functionalities in your web or desktop projects.
+Welcome to the AppFlowy Web project! This project aims to bring the powerful features of AppFlowy to the web. Whether
+you're a developer looking to contribute or a user eager to try out the latest features, this guide will help you get
+started.
-## ๐ Getting Started
+AppFlowy Web is built with the following technologies:
-### ๐ ๏ธ Prerequisites
+- **React**: A JavaScript library for building user interfaces.
+- **TypeScript**: A typed superset of JavaScript that compiles to plain JavaScript.
+- **Bun**: A fast all-in-one JavaScript runtime.
+- **Nginx**: A high-performance web server.
+- **Docker**: A platform to develop, ship, and run applications in containers.
-Before you begin, ensure you have the following installed:
+### Resource Sharing
-- Node.js (v14 or later)
-- Rust (latest stable version)
-- Tauri prerequisites for your operating system
-- PNPM (8.5.0)
+To maintain consistency across different platforms, the Web project shares i18n translation files and Icons with the
+Flutter project. This ensures a unified user experience and reduces duplication of effort in maintaining these
+resources.
-### ๐๏ธ Installation
+- **i18n Translation Files**: The translation files are shared to provide a consistent localization experience across
+ both Web and Flutter applications. The path to the translation files is `frontend/resources/translations/`.
-#### Clone the Repository
+ > The translation files are stored in JSON format and contain translations for different languages. The files are
+ named according to the language code (e.g., `en.json` for English, `es.json` for Spanish, etc.).
- ```bash
- git clone https://github.com/AppFlowy-IO/AppFlowy
- ```
+- **Icons**: The icon set used in the Web project is the same as the one used in the Flutter project, ensuring visual
+ consistency. The icons are stored in the `frontend/resources/flowy_icons/` directory.
-#### ๐ Install the frontend dependencies:
+Let's dive in and get the project up and running! ๐
- ```bash
- cd frontend/appflowy_web_app
- pnpm install
- ```
+## ๐ Getting Started
-#### ๐ฅ๏ธ Desktop Application (Tauri) (Optional)
+### Prerequisites
-> **Note**: if you want to run the web app in the browser, skip this step
+Before you begin, make sure you have the following installed on your system:
-- Follow the instructions [here](https://tauri.app/v1/guides/getting-started/prerequisites/) to install Tauri
+- [Node.js](https://nodejs.org/) (v18.6.0) ๐ณ
+- [pnpm](https://pnpm.io/) (package manager) ๐ฆ
+- [Jest](https://jestjs.io/) (testing framework) ๐
+- [Cypress](https://www.cypress.io/) (end-to-end testing) ๐งช
-##### Windows and Linux Prerequisites
+### Clone the Repository
-###### Windows only
+First, clone the repository to your local machine:
-- Install the Duckscript CLI and vcpkg
+```bash
+git clone https://github.com/AppFlowy-IO/AppFlowy.git
+cd frontend/appflowy_web_app
+```
- ```bash
- cargo install --force duckscript_cli
- vcpkg integrate install
- ```
+### Install Dependencies
-###### Linux only
+Install the required dependencies using pnpm:
-- Install the required dependencies
+```bash
+## ensure you have pnpm installed, if not run the following command
+# npm install -g pnpm@8.5.0
- ```bash
- sudo apt-get update
- sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf
- ```
+pnpm install
+```
-- **Get error**: failed to run custom build command for librocksdb-sys v6.11.4
+### Start the Development Server
- ```bash
- sudo apt install clang
- ```
+To start the development server, run the following command:
-##### Install Tauri Dependencies
+```bash
+pnpm run dev
+```
-- Install cargo-make
+### ๐ Building for Production(Optional)
- ```bash
- cargo install --force cargo-make
- ```
+if you want to run the production build, use the following commands
+```bash
+pnpm run build
+pnpm run start
+```
-- Install AppFlowy dev tools
+This will start the application in development mode. Open http://localhost:3000 to view it in the browser.
- ```bash
- # install development tools
- # make sure you are in the root directory of the project
- cd frontend
- cargo make appflowy-tauri-deps-tools
- ```
+## ๐งช Running Tests
-- Build the service/dependency
+### Unit Tests
- ```bash
- # make sure you are in the root directory of the project
- cd frontend/appflowy_web_app
- mkdir dist
- cd src-tauri
- cargo build
- ```
+We use **Jest** for running unit tests. To run the tests, use the following command:
-### ๐ Running the Application
+```bash
+pnpm run test:unit
+```
-#### ๐ Web Application
+This will execute all the unit tests in the project and provide a summary of the results. โ
-- Run the web application
+### Components Tests
- ```bash
- pnpm run dev
- ```
-- Open your browser and navigate to `http://localhost:3000`, You can now interact with the AppFlowy web application
+We use **Cypress** for end-to-end testing. To run the Cypress tests, use the following command:
-#### ๐ฅ๏ธ Desktop Application (Tauri)
+```bash
+pnpm run cypress:open
+```
-**Ensure close web application before running the desktop application**
+This will open the Cypress Test Runner where you can run your end-to-end tests. ๐งช
-- Run the desktop application
-
- ```bash
- pnpm run tauri:dev
- ```
-- The AppFlowy desktop application will open, and you can interact with it
-
-### ๐ ๏ธ Development
-
-#### How to add or modify i18n keys
-
-- Modify the i18n files in `frontend/resources/translations/en.json` to add or modify i18n keys
-- Run the following command to update the i18n keys in the application
-
- ```bash
- pnpm run sync:i18n
- ```
-
-#### How to modify the theme
-
-Don't modify the theme file in `frontend/appflowy_web_app/src/styles/variables` directly)
-
-- Modify the theme file in `frontend/appflowy_web_app/style-dictionary/tokens/base.json( or dark.json or light.json)` to
- add or modify theme keys
-- Run the following command to update the theme in the application
-
- ```bash
- pnpm run css:variables
- ```
-
-#### How to add or modify the environment variables
-
-- Modify the environment file in `frontend/appflowy_web_app/.env` to add or modify environment variables
-
-#### How to create symlink for the @appflowyinc/client-api-wasm in local development
-
-- Run the following command to create a symlink for the @appflowyinc/client-api-wasm
-
- ```bash
- # ensure you are in the frontend/appflowy_web_app directory
-
- pnpm run link:client-api $source_path $target_path
-
- # Example
- # pnpm run link:client-api ../../../AppFlowy-Cloud/libs/client-api-wasm/pkg ./node_modules/@appflowyinc/client-api-wasm
- ```
-
-### ๐ About the Project
-
-#### ๐ Directory Structure
-
-- `frontend/appflowy_web_app`: Contains the web application source code
-- `frontend/appflowy_web_app/src`: Contains the app entry point and the source code
-- `frontend/appflowy_web_app/src/components`: Contains the react components
-- `frontend/appflowy_web_app/src/styles`: Contains the styles for the application
-- `frontend/appflowy_web_app/src/utils`: Contains the utility functions
-- `frontend/appflowy_web_app/src/i18n`: Contains the i18n files
-- `frontend/appflowy_web_app/src/assets`: Contains the assets for the application
-- `frontend/appflowy_web_app/src/store`: Contains the redux store
-- `frontend/appflowy_web_app/src/@types`: Contains the typescript types
-- `frontend/appflowy_web_app/src/applications/services`: Contains the services for the application. In vite.config.ts,
- we have defined the alias for the services directory for different environments(Tauri/Web)
- ```typescript
- resolve: {
- alias: [
- // ...
- {
- find: '$client-services',
- replacement: !!process.env.TAURI_PLATFORM
- ? `${__dirname}/src/application/services/tauri-services`
- : `${__dirname}/src/application/services/js-services`,
- },
- ]
- }
- ```
-
-### ๐ฆ Deployment
-
-Use the AppFlowy CI/CD pipeline to deploy the application to the test and production environments.
-
-- Push the changes to the main branch
-- Deploy Test Environment
- - Automatically, the test environment will be deployed if merged to the main branch or build/test branch
-- Deploy Production Environment
- - Navigate to the Actions tab
- - Click on the workflow and select the Run workflow
- - Enter the options
- - Click on the Run workflow button
-
-#### ๐ฆ Deployment (Self-Hosted EC2)
-
-##### Pre-requisites
-
-Please ensure you have learned about:
-
-- [Deploy Web application on AWS Cloud using EC2 Instance](https://www.youtube.com/watch?v=gWVIIU1ev0Y)
-- [How to Install and Use Rsync Command](https://operavps.com/docs/install-rsync-command-in-linux/)
-- [How to Use ssh-keygen to Generate a New SSH Key?](https://www.ssh.com/academy/ssh/keygen)
-- [Linux post-installation steps for Docker Engine](https://docs.docker.com/engine/install/linux-postinstall/)
-- [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
-
-And then follow the steps below:
-
-1. Ensure you have the following installed on your server:
- - Docker: [Install Docker](https://docs.docker.com/engine/install/)
- - Rsync: [Install Rsync](https://operavps.com/docs/install-rsync-command-in-linux/)
-
-2. Create a new user for deploy, and generate an SSH key for the user
-
- ```bash
- sudo adduser appflowy(or any name)
- sudo su - appflowy
- mkdir ~/.ssh
- chmod 700 ~/.ssh
- ssh-keygen -t rsa
- chmod 600 ~/.ssh/authorized_keys
- # add the user to the docker group, to run docker commands without sudo
- sudo usermod -aG docker ${USER}
- ```
- - visit the `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub` to get the private and public key respectively
- - add the public key to the `~/.ssh/authorized_keys` file
- - ensure the private key is kept safe
- - exit and login back to the server with the new
- user: `ssh -i your-existing-key.pem ec2-user@your-instance-public-dns`
-
-3. Clone the AppFlowy repository
-
-4. Set the following secrets in your
- repository, have to
- know [Using secrets in GitHub Actions](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions)
-
-> Note: Test Environment: prefix the secret with `WEB_TEST_` and Production Environment: prefix the secret with `WEB_`
-
-> for example, `WEB_TEST_SSH_PRIVATE_KEY` and `WEB_SSH_PRIVATE_KEY`
-
-- `SSH_PRIVATE_KEY`: The private key generated in step 2: cat ~/.ssh/id_rsa
-- `REMOTE_HOST`: The host of the server: `your-instance-public-dns` or `your-instance-ip`
-- `REMOTE_USER`: The user created in step 2: `appflowy`
-- `SSL_CERTIFICATE`: The SSL certificate for the
- server - [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
-- `SSL_CERTIFICATE_KEY`: The SSL certificate key for the
- server - [Configuring HTTPS servers](https://nginx.org/en/docs/http/configuring_https_servers.html)
-
-5. Run the deployment workflow to deploy the application(production or test environment)
-
-> Note: the test server will **automatically** deploy if merged to the main branch or build/test branch
-
-### ๐งช Testing
-
-> We use Cypress for end-to-end testing and component testing - [Cypress](https://www.cypress.io/)
-
-#### ๐งช End-to-End Testing
-
-> to be continued
-
-#### ๐งช Component Testing
-
-Run the following command to run the component tests
+Alternatively, to run Cypress tests in the headless mode, use:
```bash
pnpm run test:components
```
+Both commands will provide detailed test results and generate a code coverage report.
+
+## ๐ Development Workflow
+
+### Linting
+
+To maintain code quality, we use **ESLint**. To run the linter and fix any linting errors, use the following command:
+
+```bash
+pnpm run lint
+```
+
+## ๐ Production Deployment
+
+Our production deployment process is automated using GitHub Actions. The process involves:
+
+1. **Setting up an AWS EC2 instance**: We use an EC2 instance to host the application.
+2. **Installing Docker and Docker Compose**: Docker is installed on the AWS instance.
+3. **Configuring SSH Access**: SSH access is set up with a user and password.
+4. **Preparing Project Configuration**: We configure `Dockerfile`, `nginx.conf`, and `server.cjs` in the web project.
+5. **Using GitHub Actions**: We use the easingthemes/ssh-deploy@main action to deploy the project to the remote server.
+
+The deployment steps include building the Docker image and running the Docker container with the necessary port
+mappings:
+
+```bash
+docker build -t appflowy-web-app .
+docker rm -f appflowy-web-app || true
+docker run -d -p 80:80 -p 443:443 --name appflowy-web-app appflowy-web-app
+```
+
+The Web server runs on Bun. For more details about Bun, please refer to the [Bun documentation](https://bun.sh/).
diff --git a/frontend/appflowy_web_app/package.json b/frontend/appflowy_web_app/package.json
index f822a6b0f9..beb77ef937 100644
--- a/frontend/appflowy_web_app/package.json
+++ b/frontend/appflowy_web_app/package.json
@@ -36,6 +36,7 @@
"@mui/x-date-pickers-pro": "^6.18.2",
"@reduxjs/toolkit": "2.0.0",
"@slate-yjs/core": "^1.0.2",
+ "@tailwindcss/typography": "^0.5.13",
"@tauri-apps/api": "^1.5.3",
"@types/react-swipeable-views": "^0.13.4",
"async-retry": "^1.3.3",
@@ -43,9 +44,11 @@
"colorthief": "^2.4.0",
"dayjs": "^1.11.9",
"decimal.js": "^10.4.3",
+ "dompurify": "^3.1.5",
"emoji-mart": "^5.5.2",
"emoji-regex": "^10.2.1",
"events": "^3.3.0",
+ "eventsource-parser": "^1.1.2",
"google-protobuf": "^3.15.12",
"i18next": "^22.4.10",
"i18next-browser-languagedetector": "^7.0.1",
@@ -55,6 +58,7 @@
"js-base64": "^3.7.5",
"katex": "^0.16.7",
"lodash-es": "^4.17.21",
+ "markdown-it": "^14.1.0",
"nanoid": "^4.0.0",
"numeral": "^2.0.6",
"prismjs": "^1.29.0",
@@ -107,6 +111,7 @@
"@svgr/plugin-svgo": "^8.0.1",
"@tauri-apps/cli": "^1.5.11",
"@testing-library/react": "^16.0.0",
+ "@types/dompurify": "^3.0.5",
"@types/google-protobuf": "^3.15.12",
"@types/is-hotkey": "^0.1.7",
"@types/jest": "^29.5.3",
diff --git a/frontend/appflowy_web_app/pnpm-lock.yaml b/frontend/appflowy_web_app/pnpm-lock.yaml
index 194beaa5dd..bb66a8bf1d 100644
--- a/frontend/appflowy_web_app/pnpm-lock.yaml
+++ b/frontend/appflowy_web_app/pnpm-lock.yaml
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
dependencies:
'@appflowyinc/client-api-wasm':
specifier: 0.0.3
@@ -37,6 +41,9 @@ dependencies:
'@slate-yjs/core':
specifier: ^1.0.2
version: 1.0.2(slate@0.101.5)(yjs@13.6.15)
+ '@tailwindcss/typography':
+ specifier: ^0.5.13
+ version: 0.5.13(tailwindcss@3.2.7)
'@tauri-apps/api':
specifier: ^1.5.3
version: 1.5.6
@@ -58,6 +65,9 @@ dependencies:
decimal.js:
specifier: ^10.4.3
version: 10.4.3
+ dompurify:
+ specifier: ^3.1.5
+ version: 3.1.5
emoji-mart:
specifier: ^5.5.2
version: 5.6.0
@@ -67,6 +77,9 @@ dependencies:
events:
specifier: ^3.3.0
version: 3.3.0
+ eventsource-parser:
+ specifier: ^1.1.2
+ version: 1.1.2
google-protobuf:
specifier: ^3.15.12
version: 3.21.2
@@ -94,6 +107,9 @@ dependencies:
lodash-es:
specifier: ^4.17.21
version: 4.17.21
+ markdown-it:
+ specifier: ^14.1.0
+ version: 14.1.0
nanoid:
specifier: ^4.0.0
version: 4.0.2
@@ -246,6 +262,9 @@ devDependencies:
'@testing-library/react':
specifier: ^16.0.0
version: 16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.2.22)(@types/react@18.2.66)(react-dom@18.2.0)(react@18.2.0)
+ '@types/dompurify':
+ specifier: ^3.0.5
+ version: 3.0.5
'@types/google-protobuf':
specifier: ^3.15.12
version: 3.15.12
@@ -3363,12 +3382,10 @@ packages:
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
- dev: true
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
- dev: true
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
@@ -3376,7 +3393,6 @@ packages:
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.17.1
- dev: true
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
@@ -3821,6 +3837,18 @@ packages:
- typescript
dev: true
+ /@tailwindcss/typography@0.5.13(tailwindcss@3.2.7):
+ resolution: {integrity: sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==}
+ peerDependencies:
+ tailwindcss: '>=3.0.0 || insiders'
+ dependencies:
+ lodash.castarray: 4.4.0
+ lodash.isplainobject: 4.0.6
+ lodash.merge: 4.6.2
+ postcss-selector-parser: 6.0.10
+ tailwindcss: 3.2.7(postcss@8.4.21)
+ dev: false
+
/@tauri-apps/api@1.5.6:
resolution: {integrity: sha512-LH5ToovAHnDVe5Qa9f/+jW28I6DeMhos8bNDtBOmmnaDpPmJmYLyHdeDblAWWWYc7KKRDg9/66vMuKyq0WIeFA==}
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
@@ -4029,6 +4057,12 @@ packages:
resolution: {integrity: sha512-p9eZ2X9B80iKiTW4ukVj8B4K6q9/+xFtQ5MGYA5HWToY9nL4EkhV9+6ftT2VHpVMEZb5Tv00Iel516bVdO+yRw==}
dev: true
+ /@types/dompurify@3.0.5:
+ resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==}
+ dependencies:
+ '@types/trusted-types': 2.0.7
+ dev: true
+
/@types/eslint-scope@3.7.7:
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
dependencies:
@@ -4273,6 +4307,10 @@ packages:
resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
dev: true
+ /@types/trusted-types@2.0.7:
+ resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
+ dev: true
+
/@types/use-sync-external-store@0.0.3:
resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==}
dev: false
@@ -4609,12 +4647,10 @@ packages:
acorn: 7.4.1
acorn-walk: 7.2.0
xtend: 4.0.2
- dev: true
/acorn-walk@7.2.0:
resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
engines: {node: '>=0.4.0'}
- dev: true
/acorn-walk@8.3.2:
resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==}
@@ -4625,7 +4661,6 @@ packages:
resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
engines: {node: '>=0.4.0'}
hasBin: true
- dev: true
/acorn@8.11.3:
resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==}
@@ -4768,7 +4803,6 @@ packages:
/arg@5.0.2:
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
- dev: true
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@@ -4777,7 +4811,6 @@ packages:
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- dev: true
/aria-query@5.3.0:
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
@@ -5219,7 +5252,6 @@ packages:
/camelcase-css@2.0.1:
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
engines: {node: '>= 6'}
- dev: true
/camelcase@5.3.1:
resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
@@ -5600,7 +5632,6 @@ packages:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
hasBin: true
- dev: true
/csso@5.0.5:
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
@@ -5836,7 +5867,6 @@ packages:
/defined@1.0.1:
resolution: {integrity: sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==}
- dev: true
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
@@ -5858,11 +5888,9 @@ packages:
acorn-node: 1.8.2
defined: 1.0.1
minimist: 1.2.8
- dev: true
/didyoumean@1.2.2:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
- dev: true
/diff-sequences@29.6.3:
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
@@ -5887,7 +5915,6 @@ packages:
/dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
- dev: true
/doctrine@2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
@@ -5949,6 +5976,10 @@ packages:
domelementtype: 2.3.0
dev: true
+ /dompurify@3.1.5:
+ resolution: {integrity: sha512-lwG+n5h8QNpxtyrJW/gJWckL+1/DQiYMX8f7t8Z2AZTPw1esVrqjI63i7Zc2Gz0aKzLVMYC1V1PL/ky+aY/NgA==}
+ dev: false
+
/domutils@3.1.0:
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
dependencies:
@@ -6036,7 +6067,6 @@ packages:
/entities@4.5.0:
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
engines: {node: '>=0.12'}
- dev: true
/error-ex@1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
@@ -6384,6 +6414,11 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ /eventsource-parser@1.1.2:
+ resolution: {integrity: sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==}
+ engines: {node: '>=14.18'}
+ dev: false
+
/execa@4.1.0:
resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
engines: {node: '>=10'}
@@ -6483,7 +6518,6 @@ packages:
glob-parent: 5.1.2
merge2: 1.4.1
micromatch: 4.0.5
- dev: true
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
@@ -6496,7 +6530,6 @@ packages:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
dependencies:
reusify: 1.0.4
- dev: true
/fb-watchman@2.0.2:
resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
@@ -6790,7 +6823,6 @@ packages:
engines: {node: '>=10.13.0'}
dependencies:
is-glob: 4.0.3
- dev: true
/glob-to-regexp@0.4.1:
resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
@@ -8089,11 +8121,16 @@ packages:
/lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
- dev: true
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ /linkify-it@5.0.0:
+ resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
+ dependencies:
+ uc.micro: 2.1.0
+ dev: false
+
/listr2@3.14.0(enquirer@2.4.1):
resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
engines: {node: '>=10.0.0'}
@@ -8151,6 +8188,10 @@ packages:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: false
+ /lodash.castarray@4.4.0:
+ resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
+ dev: false
+
/lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
@@ -8165,13 +8206,16 @@ packages:
/lodash.isequal@4.5.0:
resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+ /lodash.isplainobject@4.0.6:
+ resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
+ dev: false
+
/lodash.memoize@4.1.2:
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
dev: true
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
- dev: true
/lodash.once@4.1.1:
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
@@ -8273,6 +8317,18 @@ packages:
dependencies:
tmpl: 1.0.5
+ /markdown-it@14.1.0:
+ resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ entities: 4.5.0
+ linkify-it: 5.0.0
+ mdurl: 2.0.0
+ punycode.js: 2.3.1
+ uc.micro: 2.1.0
+ dev: false
+
/material-colors@1.2.6:
resolution: {integrity: sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==}
dev: false
@@ -8285,6 +8341,10 @@ packages:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
dev: true
+ /mdurl@2.0.0:
+ resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
+ dev: false
+
/memoize-one@5.2.1:
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
dev: false
@@ -8299,7 +8359,6 @@ packages:
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
- dev: true
/micromatch@4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
@@ -8343,7 +8402,6 @@ packages:
/minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
- dev: true
/minipass@7.0.4:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
@@ -8507,7 +8565,6 @@ packages:
/object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
- dev: true
/object-inspect@1.13.1:
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
@@ -8803,7 +8860,6 @@ packages:
/pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
- dev: true
/pify@4.0.1:
resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
@@ -8854,7 +8910,6 @@ packages:
postcss-value-parser: 4.2.0
read-cache: 1.0.0
resolve: 1.22.8
- dev: true
/postcss-js@4.0.1(postcss@8.4.21):
resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==}
@@ -8864,7 +8919,6 @@ packages:
dependencies:
camelcase-css: 2.0.1
postcss: 8.4.21
- dev: true
/postcss-load-config@3.1.4(postcss@8.4.21):
resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==}
@@ -8881,7 +8935,6 @@ packages:
lilconfig: 2.1.0
postcss: 8.4.21
yaml: 1.10.2
- dev: true
/postcss-nested@6.0.0(postcss@8.4.21):
resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==}
@@ -8891,7 +8944,14 @@ packages:
dependencies:
postcss: 8.4.21
postcss-selector-parser: 6.0.16
- dev: true
+
+ /postcss-selector-parser@6.0.10:
+ resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
+ engines: {node: '>=4'}
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+ dev: false
/postcss-selector-parser@6.0.16:
resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==}
@@ -8899,11 +8959,9 @@ packages:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
- dev: true
/postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
- dev: true
/postcss@8.4.21:
resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
@@ -8912,7 +8970,6 @@ packages:
nanoid: 3.3.7
picocolors: 1.0.0
source-map-js: 1.2.0
- dev: true
/postcss@8.4.38:
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
@@ -9084,6 +9141,11 @@ packages:
pump: 2.0.1
dev: true
+ /punycode.js@2.3.1:
+ resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
+ engines: {node: '>=6'}
+ dev: false
+
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -9109,7 +9171,6 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- dev: true
/queue-tick@1.0.1:
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
@@ -9118,7 +9179,6 @@ packages:
/quick-lru@5.1.1:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
- dev: true
/quill-delta@3.6.3:
resolution: {integrity: sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==}
@@ -9621,7 +9681,6 @@ packages:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
dependencies:
pify: 2.3.0
- dev: true
/readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
@@ -9827,7 +9886,6 @@ packages:
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
- dev: true
/rfdc@1.3.1:
resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
@@ -9891,7 +9949,6 @@ packages:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
- dev: true
/rxjs@7.8.0:
resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==}
@@ -10437,7 +10494,6 @@ packages:
resolve: 1.22.8
transitivePeerDependencies:
- ts-node
- dev: true
/tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
@@ -10809,6 +10865,10 @@ packages:
hasBin: true
dev: true
+ /uc.micro@2.1.0:
+ resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
+ dev: false
+
/ufo@1.5.3:
resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
dev: true
@@ -10940,7 +11000,6 @@ packages:
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
- dev: true
/uuid@3.4.0:
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
@@ -11306,7 +11365,6 @@ packages:
/xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
- dev: true
/y-indexeddb@9.0.12(yjs@13.6.15):
resolution: {integrity: sha512-9oCFRSPPzBK7/w5vOkJBaVCQZKHXB/v6SIT+WYhnJxlEC61juqG0hBrAf+y3gmSMLFLwICNH9nQ53uscuse6Hg==}
@@ -11414,7 +11472,3 @@ packages:
resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}
engines: {node: '>=12.20'}
dev: true
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
diff --git a/frontend/appflowy_web_app/src/components/app/App.tsx b/frontend/appflowy_web_app/src/components/app/App.tsx
index d7e9037ad5..fde97fdcdb 100644
--- a/frontend/appflowy_web_app/src/components/app/App.tsx
+++ b/frontend/appflowy_web_app/src/components/app/App.tsx
@@ -1,3 +1,4 @@
+import AfChatPage from '@/pages/AFChatPage';
import FolderPage from '@/pages/FolderPage';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import ProtectedRoutes from '@/components/auth/ProtectedRoutes';
@@ -13,6 +14,7 @@ const AppMain = withAppWrapper(() => {
} />
} />
+ } />
);
});
diff --git a/frontend/appflowy_web_app/src/components/chat/Answer.tsx b/frontend/appflowy_web_app/src/components/chat/Answer.tsx
new file mode 100644
index 0000000000..283881daaa
--- /dev/null
+++ b/frontend/appflowy_web_app/src/components/chat/Answer.tsx
@@ -0,0 +1,30 @@
+import { FC, useMemo } from 'react';
+import DOMPurify from 'dompurify';
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-expect-error
+import markdownit from 'markdown-it';
+
+interface AnswerProps {
+ query: string;
+ answer: string;
+ done: boolean;
+}
+
+export const Answer: FC = ({ query, answer }) => {
+ const md = useMemo(() => markdownit(), []);
+
+ return (
+