├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .envrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .husky └── post-checkout ├── .npmrc ├── .remarkignore ├── .remarkrc.json ├── .stylelintignore ├── .stylelintrc.json ├── .vscode ├── console.code-snippets ├── extensions.json ├── operators.code-snippets └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── biome.jsonc ├── codecov.yml ├── eslint.config.mjs ├── examples ├── with-automatic-ticket-creation │ ├── CHANGELOG.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── avatars │ │ │ ├── logo.png │ │ │ └── user.png │ │ ├── markprompt.png │ │ └── markprompt.svg │ ├── src │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.js ├── with-css-modules │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── markprompt.svg │ ├── src │ │ ├── App.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ ├── markprompt.module.css │ │ └── vite-env.d.ts │ └── tsconfig.json ├── with-custom-trigger-react │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── markprompt.svg │ ├── src │ │ ├── App.module.css │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── with-custom-trigger │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── markprompt.svg │ ├── src │ │ ├── main.module.css │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ └── tsconfig.json ├── with-custom-ui │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── avatars │ │ │ ├── logo.png │ │ │ └── user.png │ │ ├── markprompt.png │ │ └── markprompt.svg │ ├── src │ │ ├── main.tsx │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.js ├── with-docusaurus-algolia │ ├── README.md │ ├── babel.config.js │ ├── docs │ │ └── intro.md │ ├── docusaurus.config.ts │ ├── package.json │ ├── sidebars.js │ ├── src │ │ ├── css │ │ │ └── custom.css │ │ ├── markprompt-config.js │ │ └── pages │ │ │ ├── index.module.css │ │ │ ├── index.tsx │ │ │ └── markdown-page.md │ ├── static │ │ └── img │ │ │ ├── docusaurus-social-card.jpg │ │ │ ├── docusaurus.png │ │ │ ├── favicon.ico │ │ │ └── logo.svg │ └── tsconfig.json ├── with-docusaurus-swizzled │ ├── CHANGELOG.md │ ├── README.md │ ├── babel.config.js │ ├── docs │ │ └── intro.md │ ├── docusaurus.config.ts │ ├── package.json │ ├── sidebars.js │ ├── src │ │ ├── css │ │ │ └── custom.css │ │ ├── pages │ │ │ ├── index.module.css │ │ │ ├── index.tsx │ │ │ └── markdown-page.md │ │ └── theme │ │ │ └── SearchBar │ │ │ └── index.tsx │ ├── static │ │ └── img │ │ │ ├── docusaurus-social-card.jpg │ │ │ ├── docusaurus.png │ │ │ ├── favicon.ico │ │ │ └── logo.svg │ └── tsconfig.json ├── with-docusaurus │ ├── README.md │ ├── babel.config.js │ ├── docs │ │ └── intro.md │ ├── docusaurus.config.ts │ ├── package.json │ ├── sidebars.js │ ├── src │ │ ├── css │ │ │ └── custom.css │ │ ├── markprompt-config.js │ │ └── pages │ │ │ ├── index.module.css │ │ │ ├── index.tsx │ │ │ └── markdown-page.md │ ├── static │ │ └── img │ │ │ ├── docusaurus-social-card.jpg │ │ │ ├── docusaurus.png │ │ │ ├── favicon.ico │ │ │ └── logo.svg │ └── tsconfig.json ├── with-embed │ ├── chatbot.html │ └── embed.html ├── with-function-calling │ ├── README.md │ ├── example.env │ ├── next-env.d.ts │ ├── package.json │ ├── pages │ │ ├── _app.tsx │ │ ├── global.css │ │ └── index.tsx │ ├── public │ │ └── markprompt.svg │ └── tsconfig.json ├── with-init │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── markprompt.svg │ ├── src │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ └── tsconfig.json ├── with-markprompt-web │ ├── index.html │ ├── package.json │ ├── public │ │ ├── avatars │ │ │ ├── logo.png │ │ │ └── user.png │ │ ├── markprompt.png │ │ └── markprompt.svg │ ├── src │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.js ├── with-next │ ├── README.md │ ├── components │ │ └── icons.tsx │ ├── next-env.d.ts │ ├── package.json │ ├── pages │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── global.css │ │ └── index.tsx │ ├── public │ │ ├── avatars │ │ │ ├── logo.png │ │ │ └── user.png │ │ └── markprompt.svg │ └── tsconfig.json ├── with-standalone-ticket-deflection │ ├── eslint.config.js │ ├── index.html │ ├── package.json │ ├── public │ │ └── markprompt.svg │ ├── src │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ └── tsconfig.json └── with-ticket-creation │ ├── CHANGELOG.md │ ├── index.html │ ├── package.json │ ├── public │ ├── avatars │ │ ├── logo.png │ │ └── user.png │ ├── markprompt.png │ └── markprompt.svg │ ├── src │ ├── main.ts │ ├── style.css │ └── vite-env.d.ts │ ├── tsconfig.json │ └── vite.config.js ├── flake.lock ├── flake.nix ├── package.json ├── packages ├── core │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── chat │ │ │ ├── index.test.ts │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── constants.ts │ │ ├── docsearch.ts │ │ ├── feedback.test.ts │ │ ├── feedback.ts │ │ ├── search.test.ts │ │ ├── search.ts │ │ ├── types.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── vitest.config.js ├── css │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── index.d.ts │ ├── markprompt.css │ └── package.json ├── docusaurus-theme-search │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ └── theme │ │ │ └── SearchBar │ │ │ └── index.tsx │ ├── tsconfig.json │ └── vitest.config.js ├── eslint-config │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── astro.ts │ │ ├── base.ts │ │ ├── index.ts │ │ ├── next.ts │ │ ├── react.ts │ │ ├── tanstack.ts │ │ ├── types │ │ │ ├── eslint-config-turbo.d.ts │ │ │ ├── eslint-plugin-jsx-a11y.d.ts │ │ │ ├── eslint-plugin-promise.d.ts │ │ │ ├── eslint-plugin-react-refresh.d.ts │ │ │ ├── eslint-plugin-react.d.ts │ │ │ ├── eslint-plugin-testing-library.d.ts │ │ │ └── next__eslint-plugin-next.d.ts │ │ └── vitest.ts │ ├── tsconfig.json │ └── turbo.json ├── react │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── __mocks__ │ │ └── zustand.ts │ ├── eslint.config.js │ ├── package.json │ ├── src │ │ ├── CreateTicketView.tsx │ │ ├── Markprompt.test.tsx │ │ ├── Markprompt.tsx │ │ ├── Menu.tsx │ │ ├── TicketDeflectionForm.tsx │ │ ├── Trigger.tsx │ │ ├── chat │ │ │ ├── Answer.tsx │ │ │ ├── AssistantMessage.tsx │ │ │ ├── ChatView.test.tsx │ │ │ ├── ChatView.tsx │ │ │ ├── ChatViewForm.tsx │ │ │ ├── DefaultToolCallsConfirmation.tsx │ │ │ ├── DefaultView.tsx │ │ │ ├── MessageAnswer.tsx │ │ │ ├── MessagePrompt.tsx │ │ │ ├── Messages.tsx │ │ │ ├── References.tsx │ │ │ ├── ThreadSelect.tsx │ │ │ ├── ThreadSidebar.tsx │ │ │ ├── aes.ts │ │ │ ├── provider.tsx │ │ │ ├── store.tsx │ │ │ ├── supabase.ts │ │ │ └── utils.ts │ │ ├── constants.test.ts │ │ ├── constants.tsx │ │ ├── context │ │ │ └── global │ │ │ │ ├── provider.tsx │ │ │ │ ├── store.ts │ │ │ │ └── utils.ts │ │ ├── feedback │ │ │ ├── Feedback.test.tsx │ │ │ ├── Feedback.tsx │ │ │ ├── csat-picker.tsx │ │ │ ├── useFeedback.test.ts │ │ │ └── useFeedback.ts │ │ ├── icons.test.tsx │ │ ├── icons.tsx │ │ ├── index.ts │ │ ├── primitives │ │ │ ├── ConditionalWrap.test.tsx │ │ │ ├── ConditionalWrap.tsx │ │ │ ├── Select.tsx │ │ │ ├── branding.test.tsx │ │ │ ├── branding.tsx │ │ │ ├── headless.test.tsx │ │ │ └── headless.tsx │ │ ├── search │ │ │ ├── SearchBoxTrigger.tsx │ │ │ ├── SearchResult.tsx │ │ │ ├── SearchView.test.tsx │ │ │ ├── SearchView.tsx │ │ │ ├── useSearch.test.ts │ │ │ └── useSearch.ts │ │ ├── test-utils.ts │ │ ├── types.ts │ │ ├── ui │ │ │ ├── navigation-menu.tsx │ │ │ ├── rich-text.tsx │ │ │ └── utils.ts │ │ ├── useAbortController.tsx │ │ ├── useDefaults.test.tsx │ │ ├── useDefaults.ts │ │ ├── useMediaQuery.ts │ │ ├── utils.test.ts │ │ └── utils.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ ├── vitest.config.ts │ └── vitest.setup.ts └── web │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── scripts │ ├── analyze.js │ ├── build.js │ ├── config.js │ ├── dev.js │ └── tsc-plugin.js │ ├── src │ ├── index.tsx │ └── init.ts │ ├── tsconfig.json │ └── vitest.config.js ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── test └── utils.ts ├── tsconfig.json ├── turbo.json └── vitest.workspace.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by 4 | `@changesets/cli`, a build tool that works with multi-package repos, or 5 | single-package repos to help you version and publish your code. You can find the 6 | full documentation for it 7 | [in our repository](https://github.com/changesets/changesets) 8 | 9 | We have a quick list of common questions to get you started engaging with this 10 | project in 11 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 12 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "access": "public", 4 | "baseBranch": "main", 5 | "changelog": [ 6 | "@changesets/changelog-github", 7 | { "repo": "markprompt/markprompt-js" } 8 | ], 9 | "commit": false, 10 | "privatePackages": false, 11 | "updateInternalDependencies": "patch", 12 | "ignore": [ 13 | "with-css-modules", 14 | "with-custom-trigger-react", 15 | "with-custom-trigger", 16 | "with-docusaurus-algolia", 17 | "with-docusaurus-swizzled", 18 | "with-docusaurus", 19 | "with-function-calling", 20 | "with-init", 21 | "with-markprompt-web", 22 | "with-next", 23 | "with-standalone-ticket-deflection" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 2 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use flake; 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | 15 | Steps to reproduce the behavior: 16 | 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Screenshots** 27 | 28 | If applicable, add screenshots to help explain your problem. 29 | 30 | **Desktop (please complete the following information):** 31 | 32 | - OS: [e.g. iOS] 33 | - Browser [e.g. chrome, safari] 34 | - Version [e.g. 22] 35 | 36 | **Smartphone (please complete the following information):** 37 | 38 | - Device: [e.g. iPhone6] 39 | - OS: [e.g. iOS8.1] 40 | - Browser [e.g. stock browser, safari] 41 | - Version [e.g. 22] 42 | 43 | **Additional context** 44 | 45 | Add any other context about the problem here. 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | 11 | A clear and concise description of what the problem is. Ex. I'm always 12 | frustrated when [...] 13 | 14 | **Describe the solution you'd like** 15 | 16 | A clear and concise description of what you want to happen. 17 | 18 | **Describe alternatives you've considered** 19 | 20 | A clear and concise description of any alternative solutions or features you've 21 | considered. 22 | 23 | **Additional context** 24 | 25 | Add any other context or screenshots about the feature request here. 26 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: [main] 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 12 | 13 | jobs: 14 | lint: 15 | runs-on: blacksmith-4vcpu-ubuntu-2204 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 2 20 | - uses: pnpm/action-setup@v4 21 | with: 22 | run_install: false 23 | - uses: useblacksmith/setup-node@v5 24 | with: 25 | node-version: 22 26 | cache: pnpm 27 | - run: pnpm install 28 | - run: pnpm lint:ci 29 | env: 30 | MARKPROMPT_PROJECT_KEY: ${{ secrets.MARKPROMPT_PROJECT_KEY }} 31 | NEXT_PUBLIC_MARKPROMPT_PROJECT_KEY: 32 | ${{ secrets.MARKPROMPT_PROJECT_KEY }} 33 | 34 | test: 35 | runs-on: blacksmith-4vcpu-ubuntu-2204 36 | steps: 37 | - uses: actions/checkout@v4 38 | with: 39 | fetch-depth: 2 40 | - uses: pnpm/action-setup@v4 41 | with: 42 | run_install: false 43 | - uses: useblacksmith/setup-node@v5 44 | with: 45 | node-version: 22 46 | cache: pnpm 47 | - run: pnpm install 48 | - run: pnpm build:packages 49 | - run: pnpm turbo run test 50 | - uses: codecov/codecov-action@v4 51 | env: 52 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 53 | 54 | bundle-size: 55 | runs-on: blacksmith-4vcpu-ubuntu-2204 56 | steps: 57 | - uses: actions/checkout@v4 58 | with: 59 | fetch-depth: 2 60 | - uses: pnpm/action-setup@v4 61 | with: 62 | run_install: false 63 | - uses: useblacksmith/setup-node@v5 64 | with: 65 | node-version: 22 66 | cache: pnpm 67 | - run: pnpm install 68 | - uses: preactjs/compressed-size-action@v2 69 | with: 70 | build-script: '"build:packages"' 71 | pattern: '{./packages/**/dist/**/*.{cjs,js},./packages/css/markprompt.css}' 72 | exclude: '{**/*.map,**/*.d.{ts,cts},**/node_modules/**,./packages/**/node_modules/**/dist/**/*,./packages/eslint-config/dist/**/*}' 73 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | id-token: write 13 | contents: write 14 | pull-requests: write 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: pnpm/action-setup@v4 18 | with: 19 | run_install: false 20 | - uses: actions/setup-node@v4 21 | with: 22 | node-version: 22 23 | cache: pnpm 24 | - run: pnpm install 25 | - uses: changesets/action@v1 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 29 | with: 30 | version: pnpm run version 31 | publish: pnpm run publish 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | *.tgz 6 | 7 | # packing 8 | dist/ 9 | .docusaurus/ 10 | .next/ 11 | build/ 12 | 13 | # testing 14 | /coverage/ 15 | **/coverage/ 16 | 17 | # production 18 | /build/ 19 | /dist/ 20 | 21 | # misc 22 | .DS_Store 23 | *.pem 24 | .idea/ 25 | .direnv/ 26 | .turbo/ 27 | 28 | # debug 29 | *.log* 30 | meta.json 31 | 32 | # local env files 33 | .env 34 | .env.* 35 | 36 | private 37 | 38 | # typescript 39 | *.tsbuildinfo 40 | -------------------------------------------------------------------------------- /.husky/post-checkout: -------------------------------------------------------------------------------- 1 | rm -f {examples,packages}/*/*.tsbuildinfo || true 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | lockfile-version = 3 2 | 3 | # https://docs.npmjs.com/generating-provenance-statements#using-third-party-package-publishing-tools 4 | provenance=true 5 | -------------------------------------------------------------------------------- /.remarkignore: -------------------------------------------------------------------------------- 1 | **/CHANGELOG.md 2 | .changeset/*.md 3 | .direnv/ 4 | -------------------------------------------------------------------------------- /.remarkrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "fences": true, 4 | "listItemIndent": "one" 5 | }, 6 | "plugins": [ 7 | "remark-frontmatter", 8 | ["remark-toc", { "tight": true }], 9 | "remark-validate-links", 10 | "unified-prettier" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | .next/ 2 | build/ 3 | coverage/ 4 | dist/ 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-standard"], 3 | "rules": { 4 | "block-no-empty": null, 5 | "custom-property-pattern": null, 6 | "declaration-block-no-shorthand-property-overrides": null, 7 | "font-family-no-duplicate-names": null, 8 | "function-linear-gradient-no-nonstandard-direction": null, 9 | "function-no-unknown": null, 10 | "keyframe-block-no-duplicate-selectors": null, 11 | "keyframe-declaration-no-important": null, 12 | "keyframes-name-pattern": null, 13 | "media-feature-name-no-unknown": null, 14 | "named-grid-areas-no-invalid": null, 15 | "no-descending-specificity": null, 16 | "no-duplicate-at-import-rules": null, 17 | "no-invalid-position-at-import-rule": null, 18 | "number-max-precision": 7, 19 | "property-no-unknown": null, 20 | "selector-anb-no-unmatchable": null, 21 | "selector-class-pattern": null, 22 | "selector-id-pattern": null, 23 | "unit-no-unknown": null 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.vscode/console.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "console.log": { 3 | "scope": "javascript,typescript,javascriptreact,typescriptreact", 4 | "prefix": "con", 5 | "body": ["console.log(\"$1\")"], 6 | "description": "console.log", 7 | }, 8 | "JSON.stringify": { 9 | "scope": "javascript,typescript,javascriptreact,typescriptreact", 10 | "prefix": "json", 11 | "body": ["console.log(\"$1\", JSON.stringify($2, null, 2));"], 12 | "description": "JSON.stringify", 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "astro-build.astro-vscode", 4 | "biomejs.biome", 5 | "bradlc.vscode-tailwindcss", 6 | "dbaeumer.vscode-eslint", 7 | "financialforce.lana", 8 | "redhat.vscode-xml", 9 | "salesforce.salesforcedx-vscode", 10 | "unifiedjs.vscode-mdx" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.vscode/operators.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Effect Gen Function": { 3 | "prefix": "egen", 4 | "body": ["Effect.gen(function* ($) {\n\t$0\n})"], 5 | "description": "Effect generator Function with $ input", 6 | }, 7 | "Gen Function": { 8 | "prefix": "gen", 9 | "body": ["function* ($) {}"], 10 | "description": "Generator Function with $ input", 11 | }, 12 | "Gen Yield * tmp": { 13 | "prefix": "yy", 14 | "body": ["yield* $($0)"], 15 | "description": "Yield generator calling $()", 16 | }, 17 | "Gen Yield *": { 18 | "prefix": "!", 19 | "body": ["yield* $($0)"], 20 | "description": "Yield generator calling $()", 21 | }, 22 | "Otel import": { 23 | "prefix": "+otel", 24 | "body": ["import * as otel from '@opentelemetry/api'\n$0"], 25 | "description": "Import OpenTelemetry", 26 | }, 27 | } 28 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.workingDirectories": [{"mode": "auto"}], 3 | "eslint.useFlatConfig": true, 4 | "prettier.requireConfig": true, 5 | "typescript.tsdk": "node_modules/typescript/lib", 6 | // parse CSS files as Tailwind 7 | "files.associations": { 8 | "*.css": "tailwindcss" 9 | }, 10 | // improve suggestions UX when working with Tailwind 11 | "editor.quickSuggestions": { 12 | "strings": "on" 13 | }, 14 | "editor.formatOnSave": true, 15 | "editor.codeActionsOnSave": { 16 | "quickfix.biome": "explicit", 17 | "source.fixAll.eslint": "explicit", 18 | }, 19 | "[typescriptreact]": { 20 | "editor.defaultFormatter": "biomejs.biome", 21 | }, 22 | "[javascript]": { 23 | "editor.defaultFormatter": "biomejs.biome" 24 | }, 25 | "[typescript]": { 26 | "editor.defaultFormatter": "biomejs.biome" 27 | }, 28 | "[json]": { 29 | "editor.defaultFormatter": "biomejs.biome" 30 | }, 31 | "[jsonc]": { 32 | "editor.defaultFormatter": "biomejs.biome" 33 | }, 34 | "[css]": { 35 | "editor.defaultFormatter": "biomejs.biome" 36 | }, 37 | "[tailwindcss]": { 38 | "editor.defaultFormatter": "biomejs.biome" 39 | }, 40 | } 41 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Getting Started 4 | 5 | To start working on Markprompt, see the GitHub 6 | _[Contributing to projects](https://docs.github.com/en/get-started/quickstart/contributing-to-projects)_ 7 | documentation. 8 | 9 | After cloning, you need to install dependencies using 10 | [npm](https://www.npmjs.com): 11 | 12 | ```sh 13 | npm ci 14 | ``` 15 | 16 | Markprompt is linted using [ESLint](https://eslint.org) and 17 | [Prettier](https://prettier.io). It is type checked using 18 | [TypeScript](https://www.typescriptlang.org). To verify your changes, run: 19 | 20 | ```sh 21 | npm run lint 22 | ``` 23 | 24 | When you open a pull request, this is also run by our GitHub Actions 25 | [ci workflow](./.github/workflows/ci.yml) to make sure all code conforms to the 26 | code quality standards. 27 | 28 | You can format all code using the `prettier` command: 29 | 30 | ```sh 31 | npx prettier --write . 32 | ``` 33 | 34 | Releases are managed using 35 | [Changesets](https://github.com/changesets/changesets). You need to add a 36 | changeset for changes that need a release. To add a changeset, run the following 37 | command, and follow the instructions from the command line: 38 | 39 | ```sh 40 | npx changeset 41 | ``` 42 | 43 | Don’t forget to commit the generated changeset! 44 | 45 | ## Releasing 46 | 47 | > **Note** This section is only for maintainers 48 | 49 | Releases are managed using 50 | [Changesets](https://github.com/changesets/changesets). If there are any 51 | [changesets](./.changeset) present, Changesets will open a pull request. Merging 52 | this pull request will publish all updated packages to npm and create a GitHub 53 | release. 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Motif 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - 'examples/' 3 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { configs } from '@markprompt/eslint-config'; 2 | 3 | export default [ 4 | { 5 | ignores: ['coverage/', 'examples/', 'packages/'], 6 | }, 7 | ...configs.base(import.meta.url, ['test/utils.ts']), 8 | { 9 | rules: { 10 | '@typescript-eslint/consistent-indexed-object-style': [ 11 | 'error', 12 | 'index-signature', 13 | ], 14 | }, 15 | }, 16 | ]; 17 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Automatic ticket creation 7 | 8 | 9 | 10 |
11 |
12 |
13 |

Click the chat button

14 |
15 |
16 |
17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-automatic-ticket-creation", 3 | "version": "0.0.20", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/web": "workspace:*", 14 | "preact": "^10.25.2", 15 | "zod": "^3.23.8" 16 | }, 17 | "devDependencies": { 18 | "vite": "^6.0.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/public/avatars/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-automatic-ticket-creation/public/avatars/logo.png -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/public/avatars/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-automatic-ticket-creation/public/avatars/user.png -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/public/markprompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-automatic-ticket-creation/public/markprompt.png -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: #737373; 7 | background-color: #f5f5f5; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | } 18 | 19 | button { 20 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 21 | } 22 | 23 | body, 24 | #app { 25 | min-height: 100vh; 26 | min-height: 100dvh; 27 | } 28 | 29 | main { 30 | position: relative; 31 | display: grid; 32 | place-items: center; 33 | width: 100%; 34 | height: 100vh; 35 | } 36 | 37 | #message { 38 | position: absolute; 39 | display: grid; 40 | place-items: center; 41 | inset: 0; 42 | } 43 | 44 | #message p { 45 | border: 1px solid #ddd; 46 | background-color: #fafafa; 47 | padding: 0.25rem 0.75rem; 48 | border-radius: 9999px; 49 | font-size: 13px; 50 | font-weight: 500; 51 | color: #222; 52 | } 53 | 54 | /* We make the container fill the entire screen to accommodate for 55 | the `display: "plain"` case. 56 | */ 57 | #markprompt { 58 | position: absolute; 59 | inset: 0; 60 | pointer-events: auto; 61 | } 62 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "skipLibCheck": true, 5 | "strict": true, 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "isolatedModules": true, 9 | "noEmit": true, 10 | "jsx": "react-jsx" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/with-automatic-ticket-creation/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | 3 | export default defineConfig({ 4 | optimizeDeps: { 5 | exclude: ['@markprompt/web', '@markprompt/css', '@markprompt/react'], 6 | }, 7 | ssr: { 8 | noExternal: ['@markprompt/css'], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /examples/with-css-modules/README.md: -------------------------------------------------------------------------------- 1 | # `with-css-modules` 2 | 3 | This example contains a reference implementation of 4 | [`@markprompt/react`](../../packages/react/README.md), styled using CSS Modules. 5 | 6 | It also contains an example of using the exported context provider to manage the 7 | state of the prompt, conditionally showing a loading state and references. 8 | -------------------------------------------------------------------------------- /examples/with-css-modules/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Markprompt + Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/with-css-modules/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-css-modules", 3 | "version": "0.0.1", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/core": "workspace:*", 13 | "@markprompt/react": "workspace:*", 14 | "@radix-ui/react-icons": "^1.3.2", 15 | "@radix-ui/react-visually-hidden": "^1.1.3", 16 | "react": "^19.0.0", 17 | "react-dom": "^19.0.0" 18 | }, 19 | "devDependencies": { 20 | "@types/react": "^19.0.1", 21 | "@types/react-dom": "^19.0.2", 22 | "vite": "^6.0.3" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /examples/with-css-modules/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/with-css-modules/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: rgb(255 255 255 / 87%); 7 | background-color: #fff; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | 15 | html { 16 | box-sizing: border-box; 17 | } 18 | 19 | *, 20 | *::before, 21 | *::after { 22 | box-sizing: inherit; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | font-family: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", 28 | Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 29 | font-weight: 400; 30 | line-height: 1.6; 31 | min-height: 100vh; 32 | min-height: 100dvh; 33 | } 34 | 35 | body, 36 | #root { 37 | min-height: 100vh; 38 | min-height: 100dvh; 39 | } 40 | -------------------------------------------------------------------------------- /examples/with-css-modules/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | import './index.css'; 7 | 8 | const root = createRoot(document.getElementById('root')!); 9 | root.render( 10 | 11 | 12 | , 13 | ); 14 | -------------------------------------------------------------------------------- /examples/with-css-modules/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-css-modules/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "skipLibCheck": true, 5 | "strict": true, 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "isolatedModules": true, 9 | "noEmit": true, 10 | "jsx": "react-jsx" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/README.md: -------------------------------------------------------------------------------- 1 | # `with-custom-trigger-react` 2 | 3 | This example contains a reference implementation of 4 | [`@markprompt/react`](../../packages/react/README.md) using a custom trigger button. -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Markprompt + Custom Trigger + React 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-custom-trigger-react", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/react": "workspace:*", 14 | "react": "^19.0.0", 15 | "react-dom": "^19.0.0" 16 | }, 17 | "devDependencies": { 18 | "@types/react": "^19.0.1", 19 | "@types/react-dom": "^19.0.2", 20 | "@vitejs/plugin-react-swc": "^3.7.2", 21 | "vite": "^6.0.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/src/App.module.css: -------------------------------------------------------------------------------- 1 | .app { 2 | display: grid; 3 | place-items: center; 4 | min-height: 100vh; 5 | min-height: 100dvh; 6 | } 7 | 8 | .centered { 9 | display: grid; 10 | place-items: center; 11 | text-align: center; 12 | } 13 | 14 | .customTrigger { 15 | all: unset; 16 | display: inline-block; 17 | text-transform: uppercase; 18 | font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 19 | Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 20 | font-size: 0.875rem; 21 | padding: 0.5rem 1rem; 22 | background-color: var(--markprompt-primary); 23 | color: var(--markprompt-primaryForeground); 24 | cursor: pointer; 25 | transition: background 0.2s ease-out, color 0.2s ease-out; 26 | } 27 | 28 | .customTrigger:hover, 29 | .customTrigger:focus, 30 | .customTrigger:active { 31 | background-color: var(--markprompt-primaryForeground); 32 | color: var(--markprompt-primary); 33 | } 34 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import '@markprompt/css'; 2 | import styles from './App.module.css'; 3 | 4 | import { Markprompt, openMarkprompt } from '@markprompt/react'; 5 | import type { JSX } from 'react'; 6 | 7 | function App(): JSX.Element { 8 | return ( 9 |
10 |
11 |

Open the Markprompt dialog

12 | 16 | 23 |
24 |
25 | ); 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: rgb(255 255 255 / 87%); 7 | background-color: #242424; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react'; 2 | import { createRoot } from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | import './index.css'; 7 | 8 | const root = createRoot(document.getElementById('root')!); 9 | 10 | root.render( 11 | 12 | 13 | , 14 | ); 15 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /examples/with-custom-trigger-react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react-swc'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/README.md: -------------------------------------------------------------------------------- 1 | # `with-custom-trigger` 2 | 3 | This example contains a reference implementation of 4 | [`@markprompt/web`](../../packages/web/README.md) using a custom trigger button. -------------------------------------------------------------------------------- /examples/with-custom-trigger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Markprompt + Custom Trigger 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-custom-trigger", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/web": "workspace:*" 14 | }, 15 | "devDependencies": { 16 | "@vitejs/plugin-react-swc": "^3.7.2", 17 | "vite": "^6.0.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/src/main.module.css: -------------------------------------------------------------------------------- 1 | .app { 2 | display: grid; 3 | place-items: center; 4 | min-height: 100vh; 5 | min-height: 100dvh; 6 | } 7 | 8 | .centered { 9 | display: grid; 10 | place-items: center; 11 | text-align: center; 12 | } 13 | 14 | .customTrigger { 15 | all: unset; 16 | display: inline-block; 17 | text-transform: uppercase; 18 | font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 19 | Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 20 | font-size: 0.875rem; 21 | padding: 0.5rem 1rem; 22 | background-color: var(--markprompt-primary); 23 | color: var(--markprompt-primaryForeground); 24 | cursor: pointer; 25 | transition: background 0.2s ease-out, color 0.2s ease-out; 26 | } 27 | 28 | .customTrigger:hover, 29 | .customTrigger:focus, 30 | .customTrigger:active { 31 | background-color: var(--markprompt-primaryForeground); 32 | color: var(--markprompt-primary); 33 | } 34 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/src/main.ts: -------------------------------------------------------------------------------- 1 | import '@markprompt/css'; 2 | import './style.css'; 3 | import { markprompt, openMarkprompt } from '@markprompt/web'; 4 | 5 | import styles from './main.module.css'; 6 | 7 | document.querySelector('#app')!.innerHTML = ` 8 |
9 |

Open the Markprompt dialog

10 | 13 |
14 |
15 | `; 16 | 17 | const el = document.querySelector('#markprompt'); 18 | 19 | if (el instanceof HTMLElement) { 20 | markprompt(import.meta.env.VITE_PROJECT_API_KEY, el, { 21 | trigger: { customElement: true }, 22 | search: { enabled: false }, 23 | }); 24 | } 25 | 26 | const trigger = document.querySelector( 27 | '#markprompt-trigger', 28 | ); 29 | 30 | if (trigger) { 31 | trigger.addEventListener('click', () => { 32 | openMarkprompt(); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: rgb(255 255 255 / 87%); 7 | background-color: #242424; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-custom-trigger/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-custom-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Markprompt Custom UI Demo 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/with-custom-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-custom-ui", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/react": "workspace:*", 14 | "@markprompt/web": "workspace:*", 15 | "react": "^19.0.0", 16 | "react-dom": "^19.0.0", 17 | "react-markdown": "^9.0.1" 18 | }, 19 | "devDependencies": { 20 | "@types/react": "^19.0.1", 21 | "@types/react-dom": "^19.0.2", 22 | "@vitejs/plugin-react": "^4.2.0", 23 | "vite": "^6.0.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/with-custom-ui/public/avatars/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-custom-ui/public/avatars/logo.png -------------------------------------------------------------------------------- /examples/with-custom-ui/public/avatars/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-custom-ui/public/avatars/user.png -------------------------------------------------------------------------------- /examples/with-custom-ui/public/markprompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-custom-ui/public/markprompt.png -------------------------------------------------------------------------------- /examples/with-custom-ui/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/with-custom-ui/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-custom-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "skipLibCheck": true, 5 | "strict": true, 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "isolatedModules": true, 9 | "noEmit": true, 10 | "jsx": "react-jsx" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/with-custom-ui/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | export default defineConfig({ 5 | plugins: [react()], 6 | optimizeDeps: { 7 | exclude: ['@markprompt/web', '@markprompt/css', '@markprompt/react'], 8 | }, 9 | ssr: { 10 | noExternal: ['@markprompt/css'], 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Tutorial Intro 6 | 7 | Let's discover **Docusaurus in less than 5 minutes**. 8 | 9 | ## Getting Started 10 | 11 | Get started by **creating a new site**. 12 | 13 | Or **try Docusaurus immediately** with 14 | **[docusaurus.new](https://docusaurus.new)**. 15 | 16 | ### What you'll need 17 | 18 | - [Node.js](https://nodejs.org/en/download/) version 16.14 or above: 19 | - When installing Node.js, you are recommended to check all checkboxes related 20 | to dependencies. 21 | 22 | ## Generate a new site 23 | 24 | Generate a new Docusaurus site using the **classic template**. 25 | 26 | The classic template will automatically be added to your project after you run 27 | the command: 28 | 29 | ```bash 30 | npm init docusaurus@latest my-website classic 31 | ``` 32 | 33 | You can type this command into Command Prompt, Powershell, Terminal, or any 34 | other integrated terminal of your code editor. 35 | 36 | The command also installs all necessary dependencies you need to run Docusaurus. 37 | 38 | ## Start your site 39 | 40 | Run the development server: 41 | 42 | ```bash 43 | cd my-website 44 | npm run start 45 | ``` 46 | 47 | The `cd` command changes the directory you're working with. In order to work 48 | with your newly created Docusaurus site, you'll need to navigate the terminal 49 | there. 50 | 51 | The `npm run start` command builds your website locally and serves it through a 52 | development server, ready for you to view at http://localhost:3000/. 53 | 54 | Open `docs/intro.md` (this page) and edit some lines: the site **reloads 55 | automatically** and displays your changes. 56 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-docusaurus-algolia", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "build": "docusaurus build", 7 | "clear": "docusaurus clear", 8 | "deploy": "docusaurus deploy", 9 | "docusaurus": "docusaurus", 10 | "serve": "docusaurus serve", 11 | "start": "docusaurus start", 12 | "swizzle": "docusaurus swizzle", 13 | "typecheck": "tsc", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "write-translations": "docusaurus write-translations" 16 | }, 17 | "browserslist": { 18 | "production": [">0.5%", "not dead", "not op_mini all"], 19 | "development": [ 20 | "last 1 chrome version", 21 | "last 1 firefox version", 22 | "last 1 safari version" 23 | ] 24 | }, 25 | "dependencies": { 26 | "@algolia/client-search": "^4.23.3", 27 | "@docusaurus/core": "^3.2.1", 28 | "@docusaurus/module-type-aliases": "^3.2.1", 29 | "@docusaurus/preset-classic": "^3.2.1", 30 | "@markprompt/docusaurus-theme-search": "workspace:*", 31 | "@mdx-js/react": "^3.1.0", 32 | "acorn": "^8.14.0", 33 | "prism-react-renderer": "^2.3.1", 34 | "react": "^19.0.0", 35 | "react-dom": "^19.0.0", 36 | "search-insights": "^2.17.3" 37 | }, 38 | "devDependencies": { 39 | "@docusaurus/tsconfig": "^3.2.1", 40 | "dotenv": "^16.4.5" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/sidebars.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 2 | const sidebars = { 3 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], 4 | }; 5 | 6 | module.exports = sidebars; 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/src/markprompt-config.js: -------------------------------------------------------------------------------- 1 | // Custom link mapping functions: https://markprompt.com/docs#link-mapping 2 | if (typeof window !== 'undefined') { 3 | window.markpromptConfigExtras = { 4 | references: { 5 | // Example link mapping for references: 6 | // getHref: (reference) => reference.file?.path?.replace(/\.[^.]+$/, ''), 7 | // getLabel: (reference) => reference.meta?.leadHeading?.value || reference.file?.title, 8 | }, 9 | search: { 10 | // Example link mapping for search results (e.g. Algolia): 11 | getHref: (result) => result.url, 12 | getHeading: (result) => result.hierarchy?.lvl0, 13 | getTitle: (result) => result.hierarchy?.lvl1, 14 | getSubtitle: (result) => result.hierarchy?.lvl2, 15 | }, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | margin: 0 auto; 3 | max-width: 80ch; 4 | padding: 2em 0; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from './index.module.css'; 2 | import type { JSX } from 'react'; 3 | import Layout from '@theme/Layout'; 4 | 5 | export default function Home(): JSX.Element { 6 | return ( 7 | 8 |
9 |

Markprompt + Algolia demo

10 |

11 | This is the demo of the{' '} 12 | @markprompt/docusaurus-theme-search plugin. 13 |

14 |

Click the button at the bottom right to open Markprompt.

15 |
16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus-algolia/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus-algolia/static/img/docusaurus.png -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus-algolia/static/img/favicon.ico -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus-algolia/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@docusaurus/tsconfig", 3 | "references": [{ "path": "../../packages/docusaurus-theme-search" }], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@site/*": ["./*"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # with-docusaurus-swizzled 2 | 3 | ## 0.0.3 4 | 5 | ### Patch Changes 6 | 7 | - Updated dependencies 8 | [[`b607149`](https://github.com/markprompt/markprompt-js/commit/b60714904c2481da40801e16acc2a3c4b0717f85), 9 | [`b607149`](https://github.com/markprompt/markprompt-js/commit/b60714904c2481da40801e16acc2a3c4b0717f85), 10 | [`54af915`](https://github.com/markprompt/markprompt-js/commit/54af9150ea22da96ec4cf3d283d6d8a485696a06), 11 | [`54af915`](https://github.com/markprompt/markprompt-js/commit/54af9150ea22da96ec4cf3d283d6d8a485696a06), 12 | [`54af915`](https://github.com/markprompt/markprompt-js/commit/54af9150ea22da96ec4cf3d283d6d8a485696a06)]: 13 | - @markprompt/css@0.4.0 14 | - @markprompt/docusaurus-theme-search@0.4.0 15 | - @markprompt/react@0.7.0 16 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/README.md: -------------------------------------------------------------------------------- 1 | # Example with Docusaurus swizzled search plugin 2 | 3 | This example shows you how to use Markprompt in 4 | [Docusaurus](https://docusaurus.io/) while using another theme search plugin, 5 | such as 6 | [theme-search-algolia](https://docusaurus.io/docs/api/themes/@docusaurus/theme-search-algolia). 7 | 8 | ## Installation 9 | 10 | ``` 11 | $ npm install 12 | ``` 13 | 14 | ## Local development 15 | 16 | ``` 17 | $ npm start 18 | ``` 19 | 20 | This command starts a local development server. Most changes are reflected live 21 | without having to restart the server. 22 | 23 | ## Notes 24 | 25 | If you don't have an existing search plugin installed in your Docusaurus 26 | project, you can use the Markprompt Docusaurus plugin without swizzling. Please 27 | refer to the 28 | [Docusaurus example](https://github.com/markprompt/markprompt-js/tree/main/examples/with-docusaurus) 29 | for a simpler configuration-based setup using the 30 | `@markprompt/docusaurus-theme-search` plugin. 31 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Tutorial Intro 6 | 7 | Let's discover **Docusaurus in less than 5 minutes**. 8 | 9 | ## Getting Started 10 | 11 | Get started by **creating a new site**. 12 | 13 | Or **try Docusaurus immediately** with 14 | **[docusaurus.new](https://docusaurus.new)**. 15 | 16 | ### What you'll need 17 | 18 | - [Node.js](https://nodejs.org/en/download/) version 16.14 or above: 19 | - When installing Node.js, you are recommended to check all checkboxes related 20 | to dependencies. 21 | 22 | ## Generate a new site 23 | 24 | Generate a new Docusaurus site using the **classic template**. 25 | 26 | The classic template will automatically be added to your project after you run 27 | the command: 28 | 29 | ```bash 30 | npm init docusaurus@latest my-website classic 31 | ``` 32 | 33 | You can type this command into Command Prompt, Powershell, Terminal, or any 34 | other integrated terminal of your code editor. 35 | 36 | The command also installs all necessary dependencies you need to run Docusaurus. 37 | 38 | ## Start your site 39 | 40 | Run the development server: 41 | 42 | ```bash 43 | cd my-website 44 | npm run start 45 | ``` 46 | 47 | The `cd` command changes the directory you're working with. In order to work 48 | with your newly created Docusaurus site, you'll need to navigate the terminal 49 | there. 50 | 51 | The `npm run start` command builds your website locally and serves it through a 52 | development server, ready for you to view at http://localhost:3000/. 53 | 54 | Open `docs/intro.md` (this page) and edit some lines: the site **reloads 55 | automatically** and displays your changes. 56 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/docusaurus.config.ts: -------------------------------------------------------------------------------- 1 | import type * as Preset from '@docusaurus/preset-classic'; 2 | import type { Config } from '@docusaurus/types'; 3 | import type { ThemeConfig as MarkpromptThemeConfig } from '@markprompt/docusaurus-theme-search'; 4 | import dotenv from 'dotenv'; 5 | import { themes } from 'prism-react-renderer'; 6 | 7 | dotenv.config(); 8 | 9 | const config = { 10 | title: 'Markprompt with swizzling', 11 | tagline: 'Markprompt with swizzling', 12 | favicon: 'img/favicon.ico', 13 | 14 | // Set the production url of your site here 15 | url: 'https://your-docusaurus-test-site.com', 16 | // Set the // pathname under which your site is served 17 | // For GitHub pages deployment, it is often '//' 18 | baseUrl: '/', 19 | 20 | presets: [ 21 | [ 22 | 'classic', 23 | { 24 | theme: { 25 | customCss: require.resolve('./src/css/custom.css'), 26 | }, 27 | } satisfies Preset.Options, 28 | ], 29 | ], 30 | 31 | themeConfig: { 32 | // Replace with your project's social card 33 | image: 'img/docusaurus-social-card.jpg', 34 | markprompt: { 35 | // Set the project key here, on in a `.env` file. You can obtain 36 | // the project key in the Markprompt dashboard, under 37 | // project settings. 38 | projectKey: 'YOUR-PROJECT-KEY', 39 | trigger: { floating: false }, 40 | chat: { 41 | systemPrompt: 'You are a friendly AI who loves to help people.', 42 | }, 43 | search: { enabled: true }, 44 | }, 45 | navbar: { 46 | title: 'Markprompt + Algolia demo', 47 | logo: { 48 | alt: 'My Site Logo', 49 | src: 'img/logo.svg', 50 | }, 51 | items: [ 52 | { 53 | href: 'https://github.com/markprompt/markprompt-js/blob/main/examples/with-docusaurus-swizzled', 54 | label: 'GitHub', 55 | position: 'right', 56 | }, 57 | ], 58 | }, 59 | footer: { 60 | style: 'light', 61 | copyright: `Copyright © ${new Date().getFullYear()} Markprompt. Built with Docusaurus.`, 62 | }, 63 | prism: { 64 | theme: themes.github, 65 | darkTheme: themes.dracula, 66 | }, 67 | } satisfies Preset.ThemeConfig & MarkpromptThemeConfig, 68 | } satisfies Config; 69 | 70 | module.exports = config; 71 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-docusaurus-swizzled", 3 | "version": "0.0.3", 4 | "private": true, 5 | "scripts": { 6 | "build": "docusaurus build", 7 | "clear": "docusaurus clear", 8 | "deploy": "docusaurus deploy", 9 | "docusaurus": "docusaurus", 10 | "serve": "docusaurus serve", 11 | "start": "docusaurus start", 12 | "swizzle": "docusaurus swizzle", 13 | "typecheck": "tsc", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "write-translations": "docusaurus write-translations" 16 | }, 17 | "browserslist": { 18 | "production": [">0.5%", "not dead", "not op_mini all"], 19 | "development": [ 20 | "last 1 chrome version", 21 | "last 1 firefox version", 22 | "last 1 safari version" 23 | ] 24 | }, 25 | "dependencies": { 26 | "@docusaurus/core": "^3.2.1", 27 | "@docusaurus/module-type-aliases": "^3.2.1", 28 | "@docusaurus/preset-classic": "^3.2.1", 29 | "@docusaurus/theme-search-algolia": "^3.2.1", 30 | "@markprompt/css": "workspace:*", 31 | "@markprompt/docusaurus-theme-search": "workspace:*", 32 | "@markprompt/react": "workspace:*", 33 | "@mdx-js/react": "^3.1.0", 34 | "acorn": "^8.14.0", 35 | "prism-react-renderer": "^2.3.1", 36 | "react": "^19.0.0", 37 | "react-dom": "^19.0.0" 38 | }, 39 | "devDependencies": { 40 | "@docusaurus/tsconfig": "^3.2.1", 41 | "dotenv": "^16.4.5" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/sidebars.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 2 | const sidebars = { 3 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], 4 | }; 5 | 6 | module.exports = sidebars; 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | margin: 0 auto; 3 | max-width: 80ch; 4 | padding: 2em 0; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from './index.module.css'; 2 | import type { JSX } from 'react'; 3 | import Layout from '@theme/Layout'; 4 | 5 | export default function Home(): JSX.Element { 6 | return ( 7 | 8 |
9 |

Markprompt + Algolia demo with swizzling

10 |

This demo features Markprompt with Algolia as a swizzled plugin.

11 |

Click the search bar at the top right to open Markprompt.

12 |
13 |
14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/src/theme/SearchBar/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import '@markprompt/css'; 3 | 4 | import type { WrapperProps } from '@docusaurus/types'; 5 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 6 | import type { MarkpromptConfig } from '@markprompt/docusaurus-theme-search'; 7 | import type SearchBarType from '@theme/SearchBar'; 8 | import SearchBar from '@theme-original/SearchBar'; 9 | import { Suspense, lazy, type JSX } from 'react'; 10 | 11 | // import Markprompt lazily as Docusaurus does not currently support ESM 12 | const Markprompt = lazy(() => { 13 | return import('@markprompt/react').then((mod) => ({ 14 | default: mod.Markprompt, 15 | })); 16 | }); 17 | 18 | type Props = WrapperProps; 19 | 20 | export default function SearchBarWrapper(props: Props): JSX.Element { 21 | const { siteConfig } = useDocusaurusContext(); 22 | const { projectKey, ...config } = siteConfig.themeConfig 23 | .markprompt as MarkpromptConfig; 24 | 25 | return ( 26 |
27 | {/* Docusaurus' version of `ReactDOMServer` doesn't support Suspense yet, so we can only render the component on the client. */} 28 | {typeof window !== 'undefined' && ( 29 | 30 | 31 | 32 | )} 33 | 34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus-swizzled/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus-swizzled/static/img/docusaurus.png -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus-swizzled/static/img/favicon.ico -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus-swizzled/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@docusaurus/tsconfig", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@site/*": ["./*"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/with-docusaurus/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/with-docusaurus/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Tutorial Intro 6 | 7 | Let's discover **Docusaurus in less than 5 minutes**. 8 | 9 | ## Getting Started 10 | 11 | Get started by **creating a new site**. 12 | 13 | Or **try Docusaurus immediately** with 14 | **[docusaurus.new](https://docusaurus.new)**. 15 | 16 | ### What you'll need 17 | 18 | - [Node.js](https://nodejs.org/en/download/) version 16.14 or above: 19 | - When installing Node.js, you are recommended to check all checkboxes related 20 | to dependencies. 21 | 22 | ## Generate a new site 23 | 24 | Generate a new Docusaurus site using the **classic template**. 25 | 26 | The classic template will automatically be added to your project after you run 27 | the command: 28 | 29 | ```bash 30 | npm init docusaurus@latest my-website classic 31 | ``` 32 | 33 | You can type this command into Command Prompt, Powershell, Terminal, or any 34 | other integrated terminal of your code editor. 35 | 36 | The command also installs all necessary dependencies you need to run Docusaurus. 37 | 38 | ## Start your site 39 | 40 | Run the development server: 41 | 42 | ```bash 43 | cd my-website 44 | npm run start 45 | ``` 46 | 47 | The `cd` command changes the directory you're working with. In order to work 48 | with your newly created Docusaurus site, you'll need to navigate the terminal 49 | there. 50 | 51 | The `npm run start` command builds your website locally and serves it through a 52 | development server, ready for you to view at http://localhost:3000/. 53 | 54 | Open `docs/intro.md` (this page) and edit some lines: the site **reloads 55 | automatically** and displays your changes. 56 | -------------------------------------------------------------------------------- /examples/with-docusaurus/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-docusaurus", 3 | "version": "0.0.2", 4 | "private": true, 5 | "scripts": { 6 | "build": "docusaurus build", 7 | "clear": "docusaurus clear", 8 | "deploy": "docusaurus deploy", 9 | "docusaurus": "docusaurus", 10 | "serve": "docusaurus serve", 11 | "start": "docusaurus start", 12 | "swizzle": "docusaurus swizzle", 13 | "typecheck": "tsc", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "write-translations": "docusaurus write-translations" 16 | }, 17 | "browserslist": { 18 | "production": [">0.5%", "not dead", "not op_mini all"], 19 | "development": [ 20 | "last 1 chrome version", 21 | "last 1 firefox version", 22 | "last 1 safari version" 23 | ] 24 | }, 25 | "dependencies": { 26 | "@algolia/client-search": "^4.23.3", 27 | "@docusaurus/core": "^3.2.1", 28 | "@docusaurus/module-type-aliases": "^3.2.1", 29 | "@docusaurus/preset-classic": "^3.2.1", 30 | "@markprompt/docusaurus-theme-search": "workspace:*", 31 | "@mdx-js/react": "^3.1.0", 32 | "acorn": "^8.14.0", 33 | "prism-react-renderer": "^2.3.1", 34 | "react": "^19.0.0", 35 | "react-dom": "^19.0.0", 36 | "search-insights": "^2.17.3" 37 | }, 38 | "devDependencies": { 39 | "@docusaurus/tsconfig": "^3.2.1", 40 | "dotenv": "^16.4.5" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/with-docusaurus/sidebars.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 2 | const sidebars = { 3 | tutorialSidebar: [{ type: 'autogenerated', dirName: '.' }], 4 | }; 5 | 6 | module.exports = sidebars; 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus/src/markprompt-config.js: -------------------------------------------------------------------------------- 1 | // Custom link mapping functions: https://markprompt.com/docs#link-mapping 2 | if (typeof window !== 'undefined') { 3 | window.markpromptConfigExtras = { 4 | references: { 5 | // Example link mapping for references: 6 | // getHref: (reference) => reference.file?.path?.replace(/\.[^.]+$/, ''), 7 | // getLabel: (reference) => reference.meta?.leadHeading?.value || reference.file?.title, 8 | }, 9 | search: { 10 | // Example link mapping for search results (e.g. Algolia): 11 | // getHref: (result) => result.url, 12 | // getHeading: (result) => result.hierarchy?.lvl0, 13 | // getTitle: (result) => result.hierarchy?.lvl1, 14 | // getSubtitle: (result) => result.hierarchy?.lvl2, 15 | }, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /examples/with-docusaurus/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .main { 2 | margin: 0 auto; 3 | max-width: 80ch; 4 | padding: 2em 0; 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Layout from '@theme/Layout'; 2 | import type React from 'react'; 3 | 4 | import styles from './index.module.css'; 5 | 6 | export default function Home(): React.JSX.Element { 7 | return ( 8 | 9 |
10 |

Markprompt demo

11 |

12 | This is the demo of the{' '} 13 | @markprompt/docusaurus-theme-search plugin. 14 |

15 |

Click the button at the bottom right to open Markprompt.

16 |
17 |
18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-docusaurus/src/pages/markdown-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Markdown page example 3 | --- 4 | 5 | # Markdown page example 6 | 7 | You don't need React to write simple standalone pages. 8 | -------------------------------------------------------------------------------- /examples/with-docusaurus/static/img/docusaurus-social-card.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus/static/img/docusaurus-social-card.jpg -------------------------------------------------------------------------------- /examples/with-docusaurus/static/img/docusaurus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus/static/img/docusaurus.png -------------------------------------------------------------------------------- /examples/with-docusaurus/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-docusaurus/static/img/favicon.ico -------------------------------------------------------------------------------- /examples/with-docusaurus/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/with-docusaurus/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@docusaurus/tsconfig", 3 | "references": [{ "path": "../../packages/docusaurus-theme-search" }], 4 | "compilerOptions": { 5 | "baseUrl": ".", 6 | "paths": { 7 | "@site/*": ["./*"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/with-embed/chatbot.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Embed Demo | Markprompt 4 | 10 | 11 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/with-embed/embed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Embed Demo | Markprompt 4 | 19 | 20 | 29 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /examples/with-function-calling/README.md: -------------------------------------------------------------------------------- 1 | # `with-next` 2 | 3 | This example contains a reference implementation of 4 | [`@markprompt/react`](../../packages/react/README.md) with 5 | [Next.js](https://nextjs.org), and showcases the use for [OpenAI function calling](https://platform.openai.com/docs/guides/function-calling). -------------------------------------------------------------------------------- /examples/with-function-calling/example.env: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_PROJECT_API_KEY= 2 | NEXT_PUBLIC_MARKPROMPT_API_URL= -------------------------------------------------------------------------------- /examples/with-function-calling/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/with-function-calling/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-function-calling", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "next build", 8 | "dev": "next dev", 9 | "start": "next start" 10 | }, 11 | "dependencies": { 12 | "@markprompt/core": "workspace:*", 13 | "@markprompt/css": "workspace:*", 14 | "@radix-ui/react-icons": "^1.3.2", 15 | "@radix-ui/react-visually-hidden": "^1.1.3", 16 | "classnames": "^2.5.1", 17 | "next": "15.1.0", 18 | "openai": "^4.80.1", 19 | "react": "^19.0.0", 20 | "react-dom": "^19.0.0" 21 | }, 22 | "devDependencies": { 23 | "@types/react": "^19.0.1", 24 | "@types/react-dom": "^19.0.2" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/with-function-calling/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '@markprompt/css'; 2 | import './global.css'; 3 | 4 | import type { AppProps } from 'next/app'; 5 | import type { JSX } from 'react'; 6 | 7 | export default function App({ Component, pageProps }: AppProps): JSX.Element { 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /examples/with-function-calling/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/with-function-calling/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "eslint.config.mjs"], 3 | "exclude": ["**/node_modules", ".next/"], 4 | "compilerOptions": { 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "incremental": true, 9 | "isolatedModules": true, 10 | "jsx": "preserve", 11 | "lib": ["dom", "dom.iterable", "esnext"], 12 | "module": "esnext", 13 | "moduleResolution": "bundler", 14 | "noEmit": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "es2021" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-init/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/with-init/README.md: -------------------------------------------------------------------------------- 1 | # `with-init` 2 | 3 | This example contains a reference implementation of 4 | [`@markprompt/web`](../../packages/web/README.md), using a global instance of Markprompt. -------------------------------------------------------------------------------- /examples/with-init/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Markprompt Init 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/with-init/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-init", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "vite": "^6.0.3" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/with-init/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/with-init/src/main.ts: -------------------------------------------------------------------------------- 1 | import './style.css'; 2 | 3 | // @ts-expect-error - Markprompt types have not been included here 4 | window.markprompt = { 5 | projectKey: import.meta.env.VITE_PROJECT_API_KEY, 6 | options: { 7 | chat: { 8 | assistantId: import.meta.env.VITE_ASSISTANT_ID, 9 | }, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /examples/with-init/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: rgb(255 255 255 / 87%); 7 | background-color: #fff; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | display: flex; 18 | place-items: center; 19 | min-width: 320px; 20 | min-height: 100vh; 21 | } 22 | 23 | #app { 24 | max-width: 1280px; 25 | margin: 0 auto; 26 | padding: 2rem; 27 | text-align: center; 28 | } 29 | -------------------------------------------------------------------------------- /examples/with-init/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-init/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "bundler", 8 | "strict": true, 9 | "resolveJsonModule": true, 10 | "isolatedModules": true, 11 | "esModuleInterop": true, 12 | "noEmit": true, 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "skipLibCheck": true 17 | }, 18 | "include": ["src"] 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Markprompt Web Component 7 | 8 | 9 | 10 |
11 |
12 |
13 |

Click the chat button

14 |
15 |
16 |
17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-markprompt-web", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/web": "workspace:*", 14 | "preact": "^10.25.2" 15 | }, 16 | "devDependencies": { 17 | "vite": "^6.0.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/public/avatars/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-markprompt-web/public/avatars/logo.png -------------------------------------------------------------------------------- /examples/with-markprompt-web/public/avatars/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-markprompt-web/public/avatars/user.png -------------------------------------------------------------------------------- /examples/with-markprompt-web/public/markprompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-markprompt-web/public/markprompt.png -------------------------------------------------------------------------------- /examples/with-markprompt-web/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: #737373; 7 | background-color: #f5f5f5; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | } 18 | 19 | button { 20 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 21 | } 22 | 23 | body, 24 | #app { 25 | min-height: 100vh; 26 | min-height: 100dvh; 27 | } 28 | 29 | main { 30 | position: relative; 31 | display: grid; 32 | place-items: center; 33 | width: 100%; 34 | height: 100vh; 35 | } 36 | 37 | #message { 38 | position: absolute; 39 | display: grid; 40 | place-items: center; 41 | inset: 0; 42 | } 43 | 44 | #message p { 45 | border: 1px solid #ddd; 46 | background-color: #fafafa; 47 | padding: 0.25rem 0.75rem; 48 | border-radius: 9999px; 49 | font-size: 13px; 50 | font-weight: 500; 51 | color: #222; 52 | } 53 | 54 | /* We make the container fill the entire screen to accommodate for 55 | the `display: "plain"` case. 56 | */ 57 | #markprompt { 58 | position: absolute; 59 | inset: 0; 60 | pointer-events: auto; 61 | } 62 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "skipLibCheck": true, 5 | "strict": true, 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "isolatedModules": true, 9 | "noEmit": true, 10 | "jsx": "react-jsx" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/with-markprompt-web/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | 3 | export default defineConfig({ 4 | optimizeDeps: { 5 | exclude: ['@markprompt/web', '@markprompt/css', '@markprompt/react'], 6 | }, 7 | ssr: { 8 | noExternal: ['@markprompt/css'], 9 | }, 10 | }); 11 | -------------------------------------------------------------------------------- /examples/with-next/README.md: -------------------------------------------------------------------------------- 1 | # `with-next` 2 | 3 | This example contains a reference implementation of 4 | [`@markprompt/react`](../../packages/react/README.md) with 5 | [Next.js](https://nextjs.org), and featuring [Algolia](https://algolia.com/) docs search. 6 | 7 | 8 | 9 | https://github.com/markprompt/markprompt-js/assets/504893/6b9809d7-2ac7-44a3-9ae8-8b017441da7d 10 | 11 | 12 | 13 | ## Getting Started 14 | 15 | Create a `.env.local` file at the root of the project, and add the following: 16 | 17 | ``` 18 | NEXT_PUBLIC_MARKPROMPT_PROJECT_KEY= 19 | NEXT_PUBLIC_ALGOLIA_API_KEY= 20 | NEXT_PUBLIC_ALGOLIA_APP_ID= 21 | NEXT_PUBLIC_ALGOLIA_INDEX_NAME= 22 | ``` 23 | 24 | Install dependencies and start the local dev server: 25 | 26 | ```sh 27 | npm install 28 | npm run dev 29 | ``` 30 | 31 | Open http://localhost:3000 and see the result. 32 | 33 | ## Documentation 34 | 35 | To use the Markprompt platform as is, please refer to the 36 | [Markprompt documentation](https://markprompt.com/docs). 37 | 38 | ## Community 39 | 40 | - [X](https://x.com/markprompt) 41 | 42 | ## Authors 43 | 44 | This library is created by the team behind [Markprompt](https://markprompt.com) 45 | ([@markprompt](https://x.com/markprompt)). 46 | -------------------------------------------------------------------------------- /examples/with-next/components/icons.tsx: -------------------------------------------------------------------------------- 1 | import type { ComponentPropsWithoutRef, JSX } from 'react'; 2 | 3 | const SearchIcon = (props: ComponentPropsWithoutRef<'svg'>): JSX.Element => ( 4 | // biome-ignore lint/a11y/noSvgWithoutTitle: label/hidden via props 5 | 12 | 17 | 18 | ); 19 | 20 | export { SearchIcon }; 21 | -------------------------------------------------------------------------------- /examples/with-next/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/with-next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-next", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "next build", 8 | "dev": "next dev", 9 | "start": "next start" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/react": "workspace:*", 14 | "@radix-ui/react-icons": "^1.3.2", 15 | "@radix-ui/react-visually-hidden": "^1.1.3", 16 | "classnames": "^2.5.1", 17 | "next": "15.1.0", 18 | "react": "^19.0.0", 19 | "react-dom": "^19.0.0" 20 | }, 21 | "devDependencies": { 22 | "@types/react": "^19.0.1", 23 | "@types/react-dom": "^19.0.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/with-next/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import '@markprompt/css'; 2 | import './global.css'; 3 | 4 | import type { AppProps } from 'next/app'; 5 | import type { JSX } from 'react'; 6 | 7 | export default function App({ Component, pageProps }: AppProps): JSX.Element { 8 | return ( 9 |
10 | 11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /examples/with-next/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from 'next/document'; 2 | import Script from 'next/script'; 3 | import type { JSX } from 'react'; 4 | 5 | export default function Document(): JSX.Element { 6 | return ( 7 | 8 | 9 | 10 | 11 | 15 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/with-standalone-ticket-deflection/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-standalone-ticket-deflection", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/web": "workspace:*" 14 | }, 15 | "devDependencies": { 16 | "vite": "^6.0.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/with-standalone-ticket-deflection/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/with-standalone-ticket-deflection/src/main.ts: -------------------------------------------------------------------------------- 1 | import '@markprompt/css'; 2 | import './style.css'; 3 | 4 | import { ticketDeflectionForm } from '@markprompt/web'; 5 | 6 | const el = document.querySelector('#ticket-deflection-form'); 7 | 8 | const renderTicketDeflectionForm = (): void => { 9 | if (!el || !(el instanceof HTMLElement)) return; 10 | ticketDeflectionForm(el, { 11 | projectKey: import.meta.env.VITE_MARKPROMPT_PROJECT_KEY, 12 | apiUrl: 'http://api.localhost:3000', 13 | }); 14 | }; 15 | 16 | renderTicketDeflectionForm(); 17 | -------------------------------------------------------------------------------- /examples/with-standalone-ticket-deflection/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | background-color: oklch(98% 0 0deg); 7 | color: oklch(55.5% 0 0deg); 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | 14 | body { 15 | margin: 0; 16 | min-width: 100dvw; 17 | min-height: 100dvh; 18 | } 19 | 20 | #app { 21 | min-height: 100dvh; 22 | display: flex; 23 | justify-content: center; 24 | align-items: center; 25 | padding: 2vh 2vw; 26 | } 27 | 28 | #ticket-deflection-form { 29 | flex: 1 1 auto; 30 | max-width: 37.5rem; 31 | } 32 | -------------------------------------------------------------------------------- /examples/with-standalone-ticket-deflection/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-standalone-ticket-deflection/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": true, 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 8 | "skipLibCheck": true, 9 | 10 | /* Bundler mode */ 11 | "moduleResolution": "bundler", 12 | "allowImportingTsExtensions": true, 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "noEmit": true, 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": [".", "eslint.config.js"], 24 | "exclude": ["node_modules", "dist"] 25 | } 26 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Markprompt Web Component 7 | 8 | 9 | 10 |
11 |
12 |
13 |

Click the chat button

14 |
15 |
16 |
17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "with-ticket-creation", 3 | "version": "0.0.22", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "tsc && vite build", 8 | "dev": "vite", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@markprompt/css": "workspace:*", 13 | "@markprompt/web": "workspace:*", 14 | "preact": "^10.25.2", 15 | "randomuuid": "^1.0.1" 16 | }, 17 | "devDependencies": { 18 | "vite": "^6.0.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/public/avatars/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-ticket-creation/public/avatars/logo.png -------------------------------------------------------------------------------- /examples/with-ticket-creation/public/avatars/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-ticket-creation/public/avatars/user.png -------------------------------------------------------------------------------- /examples/with-ticket-creation/public/markprompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markprompt/markprompt-js/e14063b3370ca23da2409f7d9d4a151d866dd1d1/examples/with-ticket-creation/public/markprompt.png -------------------------------------------------------------------------------- /examples/with-ticket-creation/public/markprompt.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | color-scheme: light dark; 6 | color: #737373; 7 | background-color: #f5f5f5; 8 | font-synthesis: none; 9 | text-rendering: optimizelegibility; 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | text-size-adjust: 100%; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | } 18 | 19 | button { 20 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 21 | } 22 | 23 | body, 24 | #app { 25 | min-height: 100vh; 26 | min-height: 100dvh; 27 | } 28 | 29 | main { 30 | position: relative; 31 | display: grid; 32 | place-items: center; 33 | width: 100%; 34 | height: 100vh; 35 | } 36 | 37 | #message { 38 | position: absolute; 39 | display: grid; 40 | place-items: center; 41 | inset: 0; 42 | } 43 | 44 | #message p { 45 | border: 1px solid #ddd; 46 | background-color: #fafafa; 47 | padding: 0.25rem 0.75rem; 48 | border-radius: 9999px; 49 | font-size: 13px; 50 | font-weight: 500; 51 | color: #222; 52 | } 53 | 54 | /* We make the container fill the entire screen to accommodate for 55 | the `display: "plain"` case. 56 | */ 57 | #markprompt { 58 | position: absolute; 59 | inset: 0; 60 | pointer-events: auto; 61 | } 62 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "skipLibCheck": true, 5 | "strict": true, 6 | "module": "esnext", 7 | "moduleResolution": "bundler", 8 | "isolatedModules": true, 9 | "noEmit": true, 10 | "jsx": "react-jsx" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/with-ticket-creation/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import path from 'node:path'; 3 | 4 | export default defineConfig({ 5 | resolve: { 6 | alias: { 7 | '@markprompt/core': path.resolve(__dirname, '../../packages/core/dist'), 8 | }, 9 | }, 10 | optimizeDeps: { 11 | exclude: ['@markprompt/web', '@markprompt/css', '@markprompt/react'], 12 | }, 13 | ssr: { 14 | noExternal: ['@markprompt/css'], 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1738009863, 6 | "narHash": "sha256-KxmFlQ2j9PpDhKRXWu85bv3R2wmfkUqdpJhEwz9JN/E=", 7 | "owner": "nixos", 8 | "repo": "nixpkgs", 9 | "rev": "f898cbfddfab52593da301a397a17d0af801bbc3", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "ref": "nixpkgs-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs" 22 | } 23 | } 24 | }, 25 | "root": "root", 26 | "version": 7 27 | } 28 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs = { 4 | url = "github:nixos/nixpkgs/nixpkgs-unstable"; 5 | }; 6 | }; 7 | outputs = {nixpkgs, ...}: let 8 | systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"]; 9 | forAllSystems = nixpkgs.lib.genAttrs systems; 10 | in { 11 | formatter = forAllSystems ( 12 | system: let 13 | pkgs = nixpkgs.legacyPackages.${system}; 14 | in 15 | pkgs.alejandra 16 | ); 17 | devShells = forAllSystems ( 18 | system: let 19 | pkgs = nixpkgs.legacyPackages.${system}; 20 | node = pkgs.nodejs_22; 21 | corepackEnable = pkgs.runCommand "corepack-enable" {} '' 22 | mkdir -p $out/bin 23 | ${node}/bin/corepack enable --install-directory $out/bin 24 | ''; 25 | in { 26 | default = with pkgs; 27 | mkShell { 28 | buildInputs = [ 29 | corepackEnable 30 | node 31 | ]; 32 | }; 33 | } 34 | ); 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markprompt", 3 | "private": true, 4 | "type": "module", 5 | "workspaces": ["examples/*", "packages/*"], 6 | "scripts": { 7 | "build:packages": "turbo run build --filter @markprompt/*...", 8 | "build": "turbo run build", 9 | "clean": "git clean -fdx -e .direnv/ -e \"examples/**/.env*\" -e \".husky/\"", 10 | "fix:biome": "biome check --write", 11 | "lint:biome:ci": "biome ci --diagnostic-level=error --reporter=github", 12 | "lint:biome": "biome check --diagnostic-level=error", 13 | "lint:ci": "turbo run lint:biome:ci lint:css lint:js lint:md lint:ts", 14 | "lint:css": "stylelint \"**/*.css\"", 15 | "lint:js": "eslint .", 16 | "lint:md": "remark . --frail", 17 | "lint": "turbo run lint:biome lint:css lint:js lint:md lint:ts", 18 | "postinstall": "manypkg check", 19 | "prepare": "husky", 20 | "publish": "pnpm build:packages && changeset publish", 21 | "test:watch": "vitest watch --coverage", 22 | "test": "vitest run --coverage", 23 | "version": "changeset version && biome check --write . && pnpm install" 24 | }, 25 | "dependencies": { 26 | "@biomejs/biome": "1.9.4", 27 | "@changesets/changelog-github": "^0.5.0", 28 | "@changesets/cli": "^2.27.9", 29 | "@manypkg/cli": "^0.22.0", 30 | "@markprompt/eslint-config": "workspace:*", 31 | "@vitest/coverage-v8": "^2.1.6", 32 | "eslint": "^9.16.0", 33 | "husky": "^9.0.11", 34 | "jsdom": "^25.0.1", 35 | "prettier": "^3.4.2", 36 | "remark-cli": "^12.0.1", 37 | "remark-frontmatter": "^5.0.0", 38 | "remark-toc": "^9.0.0", 39 | "remark-validate-links": "^13.0.2", 40 | "stylelint": "^16.10.0", 41 | "stylelint-config-standard": "^36.0.1", 42 | "turbo": "^2.3.4", 43 | "typescript": "^5.7.2", 44 | "unified-prettier": "^2.0.1", 45 | "vitest": "^2.1.4" 46 | }, 47 | "optionalDependencies": { 48 | "@rollup/rollup-linux-x64-gnu": "^4.25.0" 49 | }, 50 | "packageManager": "pnpm@9.15.4+sha512.b2dc20e2fc72b3e18848459b37359a32064663e5627a51e4c74b2c29dd8e8e0491483c3abb40789cfd578bf362fb6ba8261b05f0387d76792ed6e23ea3b1b6a0", 51 | "pnpm": { 52 | "overrides": { 53 | "@types/react": "^19", 54 | "@types/react-dom": "^19", 55 | "react": "^19", 56 | "react-dom": "^19" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/core/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Motif 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/core/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { configs } from '@markprompt/eslint-config'; 2 | 3 | export default [ 4 | ...configs.base(import.meta.dirname, [ 5 | 'eslint.config.js', 6 | 'vitest.config.js', 7 | 'src/*.test.ts', 8 | 'src/*/*.test.ts', 9 | ]), 10 | { 11 | rules: { 12 | '@typescript-eslint/consistent-indexed-object-style': [ 13 | 'error', 14 | 'index-signature', 15 | ], 16 | }, 17 | }, 18 | ...configs.vitest, 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@markprompt/core", 3 | "version": "0.44.1", 4 | "repository": { 5 | "type": "git", 6 | "url": "git+https://github.com/markprompt/markprompt-js.git", 7 | "directory": "packages/core" 8 | }, 9 | "license": "MIT", 10 | "sideEffects": false, 11 | "type": "module", 12 | "exports": { 13 | "./chat": { 14 | "types": "./dist/chat/index.d.ts", 15 | "import": "./dist/chat/index.js" 16 | }, 17 | "./constants": { 18 | "types": "./dist/constants.d.ts", 19 | "import": "./dist/constants.js" 20 | }, 21 | "./feedback": { 22 | "types": "./dist/feedback.d.ts", 23 | "import": "./dist/feedback.js" 24 | }, 25 | "./search": { 26 | "types": "./dist/search.d.ts", 27 | "import": "./dist/search.js" 28 | }, 29 | "./types": { 30 | "types": "./dist/types.d.ts", 31 | "import": "./dist/types.js" 32 | }, 33 | "./utils": { 34 | "types": "./dist/utils.d.ts", 35 | "import": "./dist/utils.js" 36 | } 37 | }, 38 | "files": ["dist"], 39 | "scripts": { 40 | "build": "tsc --build", 41 | "dev": "tsc --build --watch", 42 | "lint:js": "eslint .", 43 | "lint:ts": "tsc --build --noEmit", 44 | "prepack": "tsc --build" 45 | }, 46 | "dependencies": { 47 | "@algolia/client-search": "^4.23.3", 48 | "@types/lodash-es": "^4.17.12", 49 | "defaults": "^3.0.0", 50 | "eventsource-parser": "^1.1.2", 51 | "lodash-es": "^4.17.21", 52 | "openai": "^4.80.1", 53 | "type-fest": "^4.15.0" 54 | }, 55 | "devDependencies": { 56 | "@types/defaults": "^1.0.6", 57 | "msw": "^2.6.2" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/core/src/constants.ts: -------------------------------------------------------------------------------- 1 | import type { BaseOptions } from './types.js'; 2 | 3 | export const DEFAULT_OPTIONS = { 4 | apiUrl: 'https://api.markprompt.com', 5 | } satisfies BaseOptions; 6 | 7 | export type { BaseOptions }; 8 | -------------------------------------------------------------------------------- /packages/core/src/feedback.test.ts: -------------------------------------------------------------------------------- 1 | import { http, HttpResponse } from 'msw'; 2 | import { setupServer } from 'msw/node'; 3 | import { afterAll, afterEach, beforeAll, describe, expect, test } from 'vitest'; 4 | 5 | import { DEFAULT_OPTIONS } from './constants.js'; 6 | import { submitFeedback } from './feedback.js'; 7 | 8 | let status = 200; 9 | 10 | const TEST_MESSAGE_ID = 'test-id'; 11 | 12 | const server = setupServer( 13 | http.post(`${DEFAULT_OPTIONS.apiUrl}/messages/${TEST_MESSAGE_ID}`, () => { 14 | return HttpResponse.json( 15 | status === 200 ? { status: 'ok' } : { error: 'Internal Server Error' }, 16 | { status: status }, 17 | ); 18 | }), 19 | ); 20 | 21 | beforeAll(() => { 22 | server.listen({ onUnhandledRequest: 'error' }); 23 | }); 24 | 25 | afterAll(() => { 26 | server.close(); 27 | }); 28 | 29 | afterEach(() => { 30 | status = 200; 31 | server.resetHandlers(); 32 | }); 33 | 34 | describe('submitFeedback', () => { 35 | test('requires a projectKey', async () => { 36 | // @ts-expect-error We test a missing project key. 37 | await expect(() => submitFeedback()).rejects.toThrowError( 38 | 'A projectKey is required', 39 | ); 40 | }); 41 | 42 | test('makes a request', async () => { 43 | const response = await submitFeedback( 44 | { 45 | feedback: { vote: '1' }, 46 | messageId: TEST_MESSAGE_ID, 47 | }, 48 | 'testKey', 49 | ); 50 | 51 | expect(response).toStrictEqual(undefined); 52 | }); 53 | 54 | test('throws an error on invalid status code', async () => { 55 | status = 500; 56 | 57 | await expect( 58 | submitFeedback( 59 | { 60 | feedback: { vote: '1' }, 61 | messageId: TEST_MESSAGE_ID, 62 | }, 63 | 'testKey', 64 | ), 65 | ).rejects.toThrowError('Internal Server Error'); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | export type SourceType = 2 | | 'github' 3 | | 'motif' 4 | | 'website' 5 | | 'file-upload' 6 | | 'api-upload' 7 | | 'nango' 8 | | 'salesforce'; 9 | 10 | export interface Source { 11 | id: string; 12 | type: SourceType; 13 | data?: { 14 | url?: string; 15 | domain?: string; 16 | name?: string; 17 | }; 18 | } 19 | 20 | export interface FileSectionReference extends FileSectionReferenceSectionData { 21 | /** 22 | * Referenced file. 23 | */ 24 | file: FileReferenceFileData; 25 | sectionId: number; 26 | } 27 | 28 | export interface FileSectionReferenceSectionData { 29 | /** 30 | * Metadata associated to the file section. 31 | */ 32 | meta?: { 33 | leadHeading?: { 34 | id?: string; 35 | depth?: number; 36 | value?: string; 37 | slug?: string; 38 | }; 39 | }; 40 | } 41 | 42 | export interface FileReferenceFileData { 43 | /** 44 | * File title. 45 | */ 46 | title?: string; 47 | /** 48 | * File path, e.g. URL or GitHub file path. 49 | */ 50 | path: string; 51 | /** 52 | * File metadata. 53 | */ 54 | meta?: object; 55 | /** 56 | * File source. 57 | */ 58 | source: Source; 59 | } 60 | 61 | export interface BaseOptions { 62 | apiUrl?: string; 63 | headers?: { [key: string]: string }; 64 | } 65 | -------------------------------------------------------------------------------- /packages/core/src/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from 'vitest'; 2 | 3 | import { 4 | getErrorMessage, 5 | isFileSectionReferences, 6 | isAbortError, 7 | isKeyOf, 8 | } from './utils.js'; 9 | 10 | describe('getErrorMessage', () => { 11 | test('returns error from response if present', async () => { 12 | const mockResponse = new Response(JSON.stringify({ error: 'Test error' })); 13 | const result = await getErrorMessage(mockResponse); 14 | expect(result).toBe('Test error'); 15 | }); 16 | 17 | test('returns text from response if error is not present', async () => { 18 | const mockResponse = new Response('Test text'); 19 | const result = await getErrorMessage(mockResponse); 20 | expect(result).toBe('Test text'); 21 | }); 22 | }); 23 | 24 | describe('isFileSectionReferences', () => { 25 | test('identifies FileSectionReference types', () => { 26 | const references = [ 27 | { 28 | file: { 29 | path: '/docs/some-page', 30 | source: { type: 'website' }, 31 | }, 32 | }, 33 | ]; 34 | 35 | expect(isFileSectionReferences(references)).toBe(true); 36 | }); 37 | }); 38 | 39 | describe('isAbortError', () => { 40 | test('identifies AbortError', () => { 41 | const err1 = new DOMException('AbortError'); 42 | expect(isAbortError(err1)).toBe(true); 43 | const err2 = new Error('AbortError'); 44 | expect(isAbortError(err2)).toBe(true); 45 | const err3 = new Error('Some other error'); 46 | expect(isAbortError(err3)).toBe(false); 47 | }); 48 | }); 49 | 50 | describe('isKeyOf', () => { 51 | test('identifies keys of an object', () => { 52 | const obj = { foo: 'bar' }; 53 | expect(isKeyOf(obj, 'foo')).toBeTruthy(); 54 | expect(isKeyOf(obj, 'bar')).toBeFalsy(); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; 2 | 3 | import type { FileSectionReference } from './types.js'; 4 | 5 | export type RequiredKeys = Required> & 6 | Omit; 7 | 8 | export type ArrayToUnion = T extends (infer U)[] 9 | ? U 10 | : T extends readonly (infer U)[] 11 | ? U 12 | : never; 13 | 14 | export const isKeyOf = ( 15 | obj: T, 16 | key: PropertyKey, 17 | ): key is keyof T => Object.hasOwn(obj, key); 18 | 19 | export const getErrorMessage = async (res: Response): Promise => { 20 | const text = await res.text(); 21 | 22 | try { 23 | const json: unknown = JSON.parse(text); 24 | if ( 25 | json && 26 | typeof json === 'object' && 27 | 'error' in json && 28 | typeof json.error === 'string' 29 | ) { 30 | return json?.error ?? text; 31 | } 32 | } catch { 33 | return text; 34 | } 35 | 36 | return text; 37 | }; 38 | 39 | export function isAbortError(err: unknown): err is DOMException { 40 | return ( 41 | (err instanceof DOMException && err.name === 'AbortError') || 42 | (err instanceof Error && err.message.includes('AbortError')) 43 | ); 44 | } 45 | 46 | export function isFileSectionReferences( 47 | data: unknown, 48 | ): data is FileSectionReference[] { 49 | return ( 50 | Array.isArray(data) && 51 | typeof data.at(0)?.file?.path === 'string' && 52 | typeof data.at(0)?.file?.source?.type === 'string' 53 | ); 54 | } 55 | 56 | export function getMessageTextContent(m?: { 57 | content?: null | string | ChatCompletionMessageParam['content']; 58 | }) { 59 | if (!m?.content) { 60 | return; 61 | } 62 | 63 | if (typeof m.content === 'string') { 64 | return m.content; 65 | } 66 | 67 | return m.content 68 | .map((part) => (part.type === 'text' ? part.text : '')) 69 | .join(' ') 70 | .trim(); 71 | } 72 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // base 4 | "esModuleInterop": true, 5 | "skipLibCheck": true, 6 | "target": "es2023", 7 | "moduleDetection": "force", 8 | "isolatedModules": true, 9 | "checkJs": true, 10 | 11 | // strictness 12 | "strict": true, 13 | 14 | // transpilation 15 | "module": "nodenext", 16 | "moduleResolution": "nodenext", 17 | "rootDir": "src/", 18 | "outDir": "dist/", 19 | 20 | "sourceMap": true, 21 | "declaration": true, 22 | "declarationMap": true, 23 | 24 | // runtime 25 | "lib": ["dom", "dom.iterable", "es2023"] 26 | }, 27 | "include": ["src/"], 28 | "exclude": ["**/node_modules", "src/**/*.test.ts", "dist/"] 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/vitest.config.js: -------------------------------------------------------------------------------- 1 | import { defineProject, mergeConfig } from 'vitest/config'; 2 | 3 | export default mergeConfig( 4 | { 5 | coverage: { 6 | enabled: true, 7 | provider: 'v8', 8 | include: ['./src/**/*'], 9 | }, 10 | }, 11 | defineProject({ 12 | test: { 13 | pool: 'forks', 14 | }, 15 | }), 16 | ); 17 | -------------------------------------------------------------------------------- /packages/css/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Motif 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/css/README.md: -------------------------------------------------------------------------------- 1 | # Markprompt CSS 2 | 3 | Common CSS for [Markprompt](https://markprompt.com) components. 4 | 5 |
6 |

7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 | ## Installation 16 | 17 | ```sh 18 | npm install @markprompt/css 19 | ``` 20 | 21 | ## Usage 22 | 23 | With a bundler: 24 | 25 | ```js 26 | import '@markprompt/css'; 27 | ``` 28 | 29 | With a CDN: 30 | 31 | ```html 32 | 36 | ``` 37 | 38 | This package adds styling for various CSS classes. All styling is applied using 39 | the [`:where()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:where) pseudo 40 | class, so you can override all styling manually. 41 | 42 | ## Documentation 43 | 44 | The full documentation for the package can be found on the 45 | [Markprompt docs](https://markprompt.com/docs/sdk). 46 | 47 | ## Community 48 | 49 | - [X](https://x.com/markprompt) 50 | 51 | ## Authors 52 | 53 | This library is created by the team behind [Markprompt](https://markprompt.com) 54 | ([@markprompt](https://x.com/markprompt)). 55 | 56 | ## License 57 | 58 | [MIT](./LICENSE) © [Markprompt](https://markprompt.com) 59 | -------------------------------------------------------------------------------- /packages/css/index.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | -------------------------------------------------------------------------------- /packages/css/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@markprompt/css", 3 | "version": "0.34.0", 4 | "description": "Common CSS for Markprompt components", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/markprompt/markprompt-js.git", 8 | "directory": "packages/css" 9 | }, 10 | "license": "MIT", 11 | "main": "markprompt.css", 12 | "types": "./index.d.ts", 13 | "files": ["markprompt.css", "index.d.ts"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Motif 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { configs } from '@markprompt/eslint-config'; 2 | 3 | export default [ 4 | ...configs.base(import.meta.dirname, [ 5 | 'eslint.config.js', 6 | 'vitest.config.js', 7 | ]), 8 | { 9 | rules: { 10 | '@typescript-eslint/consistent-indexed-object-style': [ 11 | 'error', 12 | 'index-signature', 13 | ], 14 | 'import-x/no-unresolved': [ 15 | 'error', 16 | { 17 | ignore: ['@docusaurus/*', '@theme/*', '@site/*'], 18 | }, 19 | ], 20 | }, 21 | }, 22 | ...configs.react, 23 | ...configs.vitest, 24 | ]; 25 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@markprompt/docusaurus-theme-search", 3 | "version": "0.32.7", 4 | "description": "Markprompt search theme for Docusaurus", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/markprompt/markprompt-js.git", 8 | "directory": "packages/docusaurus-theme-search" 9 | }, 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "type": "module", 13 | "exports": "./dist/index.js", 14 | "main": "dist/index.js", 15 | "files": ["dist", "src/theme"], 16 | "scripts": { 17 | "build": "tsc --build", 18 | "lint:js": "eslint .", 19 | "lint:ts": "tsc --build --noEmit", 20 | "prepack": "tsc --build" 21 | }, 22 | "dependencies": { 23 | "@docusaurus/types": "^3.2.1", 24 | "@markprompt/css": "workspace:*", 25 | "@markprompt/react": "workspace:*", 26 | "acorn": "^8.14.0" 27 | }, 28 | "devDependencies": { 29 | "@docusaurus/module-type-aliases": "^3.2.1", 30 | "@types/react": "^19.0.1", 31 | "react": "^19.0.0" 32 | }, 33 | "peerDependencies": { 34 | "react": "^18.3 || ^19" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | PluginModule, 3 | ThemeConfigValidationContext, 4 | } from '@docusaurus/types'; 5 | import type { MarkpromptProps } from '@markprompt/react'; 6 | 7 | export type MarkpromptConfig = MarkpromptProps; 8 | 9 | export interface ThemeConfig { 10 | markprompt?: MarkpromptConfig; 11 | } 12 | 13 | const themeSearchMarkprompt: PluginModule = async () => ({ 14 | name: '@markprompt/docusaurus-theme-search', 15 | getThemePath: () => '../dist/theme', 16 | getTypeScriptThemePath: () => '../src/theme', 17 | }); 18 | 19 | export function getSwizzleComponentList(): string[] { 20 | return ['SearchBar']; 21 | } 22 | 23 | export const validateThemeConfig = ( 24 | context: ThemeConfigValidationContext, 25 | ): ThemeConfig => { 26 | return context.themeConfig; 27 | }; 28 | 29 | export default themeSearchMarkprompt; 30 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/src/theme/SearchBar/index.tsx: -------------------------------------------------------------------------------- 1 | import '@markprompt/css'; 2 | 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import { 5 | Markprompt, 6 | type MarkpromptProps, 7 | openMarkprompt, 8 | } from '@markprompt/react'; 9 | import { useEffect, useState } from 'react'; 10 | import type { JSX } from 'react'; 11 | 12 | declare global { 13 | interface Window { 14 | markpromptConfigExtras?: { 15 | references?: MarkpromptProps['references']; 16 | search?: MarkpromptProps['search']; 17 | }; 18 | } 19 | } 20 | 21 | export default function SearchBar(): JSX.Element { 22 | const [markpromptExtras, setMarkpromptExtras] = useState<{ 23 | references?: MarkpromptProps['references']; 24 | search?: MarkpromptProps['search']; 25 | }>({}); 26 | const { siteConfig } = useDocusaurusContext(); 27 | 28 | useEffect(() => { 29 | if (typeof window === 'undefined') { 30 | return; 31 | } 32 | 33 | setMarkpromptExtras(window.markpromptConfigExtras || {}); 34 | }, []); 35 | 36 | const markpromptConfigProps = siteConfig.themeConfig 37 | .markprompt as MarkpromptProps; 38 | const markpromptProps = { 39 | ...markpromptConfigProps, 40 | references: { 41 | ...markpromptConfigProps.references, 42 | ...markpromptExtras.references, 43 | }, 44 | search: { 45 | ...markpromptConfigProps.search, 46 | ...markpromptExtras.search, 47 | }, 48 | }; 49 | 50 | if (markpromptProps.trigger?.floating) { 51 | return ; 52 | } 53 | 54 | return ( 55 | <> 56 |
57 |
58 | 70 | 77 |
78 | 79 | ); 80 | } 81 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // base 4 | "esModuleInterop": true, 5 | "skipLibCheck": true, 6 | "target": "es2023", 7 | "moduleDetection": "force", 8 | "isolatedModules": true, 9 | "checkJs": true, 10 | 11 | // strictness 12 | "strict": true, 13 | "noUncheckedIndexedAccess": true, 14 | 15 | // transpilation 16 | "module": "nodenext", 17 | "moduleResolution": "nodenext", 18 | "outDir": "dist/", 19 | "rootDir": "src/", 20 | "sourceMap": true, 21 | "declaration": true, 22 | "declarationMap": true, 23 | "jsx": "react-jsx", 24 | "verbatimModuleSyntax": true, 25 | 26 | // runtime 27 | "lib": ["dom", "dom.iterable", "es2023"], 28 | 29 | "types": ["@docusaurus/module-type-aliases"] 30 | }, 31 | "include": ["src/"], 32 | "exclude": ["**/node_modules", "dist/", ".turbo/"] 33 | } 34 | -------------------------------------------------------------------------------- /packages/docusaurus-theme-search/vitest.config.js: -------------------------------------------------------------------------------- 1 | import { defineProject } from 'vitest/config'; 2 | 3 | export default defineProject({}); 4 | -------------------------------------------------------------------------------- /packages/eslint-config/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { configs } from './dist/index.js'; 2 | 3 | export default [ 4 | ...configs.base(import.meta.dirname, ['eslint.config.js']), 5 | { 6 | rules: { 7 | '@typescript-eslint/consistent-indexed-object-style': [ 8 | 'error', 9 | 'index-signature', 10 | ], 11 | }, 12 | }, 13 | ]; 14 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@markprompt/eslint-config", 3 | "private": true, 4 | "type": "module", 5 | "exports": { 6 | ".": "./dist/index.js" 7 | }, 8 | "scripts": { 9 | "build": "tsc --build", 10 | "dev": "tsc --build --watch", 11 | "lint:js": "eslint .", 12 | "lint:ts": "tsc --build --noEmit" 13 | }, 14 | "dependencies": { 15 | "@eslint/compat": "^1.2.4", 16 | "@eslint/js": "^9.16.0", 17 | "@next/eslint-plugin-next": "^14.2.15", 18 | "@tanstack/eslint-plugin-query": "^5.62.1", 19 | "@tanstack/eslint-plugin-router": "^1.92.7", 20 | "@vitest/eslint-plugin": "^1.1.14", 21 | "eslint-config-turbo": "^2.3.3", 22 | "eslint-import-resolver-typescript": "^3.7.0", 23 | "eslint-plugin-astro": "^1.3.1", 24 | "eslint-plugin-import-x": "^4.5.0", 25 | "eslint-plugin-jsx-a11y": "^6.10.2", 26 | "eslint-plugin-promise": "^7.2.1", 27 | "eslint-plugin-react": "^7.37.2", 28 | "eslint-plugin-react-refresh": "^0.4.16", 29 | "eslint-plugin-testing-library": "^7.1.0", 30 | "globals": "^15.13.0", 31 | "typescript-eslint": "^8.17.0" 32 | }, 33 | "devDependencies": { 34 | "@types/eslint__js": "^8.42.3", 35 | "@types/node": "^22", 36 | "eslint": "^9.16.0" 37 | }, 38 | "peerDependencies": { 39 | "eslint": ">= 9" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/eslint-config/src/astro.ts: -------------------------------------------------------------------------------- 1 | import type { Linter } from 'eslint'; 2 | import { configs } from 'eslint-plugin-astro'; 3 | 4 | export const astro: Linter.Config[] = [ 5 | ...configs.recommended, 6 | ...configs['jsx-a11y-recommended'], 7 | { 8 | files: ['**/*.astro'], 9 | settings: { 10 | 'import-x/extensions': ['.astro', '.js', '.jsx', '.ts', '.tsx'], 11 | 'import-x/parsers': { 12 | 'astro-eslint-parser': ['.astro'], 13 | }, 14 | }, 15 | rules: { 16 | 'import-x/default': 'off', 17 | }, 18 | }, 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/eslint-config/src/index.ts: -------------------------------------------------------------------------------- 1 | import { astro } from './astro.js'; 2 | import { base } from './base.js'; 3 | import { next } from './next.js'; 4 | import { react } from './react.js'; 5 | import { tanstack } from './tanstack.js'; 6 | import { vitest } from './vitest.js'; 7 | 8 | export const configs = { 9 | astro: astro, 10 | base: base, 11 | next: next, 12 | react: react, 13 | tanstack: tanstack, 14 | vitest: vitest, 15 | } as const; 16 | -------------------------------------------------------------------------------- /packages/eslint-config/src/next.ts: -------------------------------------------------------------------------------- 1 | import { fixupPluginRules } from '@eslint/compat'; 2 | import nextPlugin from '@next/eslint-plugin-next'; 3 | import type { Linter } from 'eslint'; 4 | 5 | export const next: Linter.Config[] = [ 6 | { 7 | ignores: ['.next/'], 8 | }, 9 | { 10 | name: 'next', 11 | plugins: { '@next/next': fixupPluginRules(nextPlugin) }, 12 | rules: { 13 | ...(nextPlugin.configs?.recommended as Linter.Config) 14 | .rules, 15 | ...( 16 | nextPlugin.configs?.[ 17 | 'core-web-vitals' 18 | ] as Linter.Config 19 | ).rules, 20 | }, 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /packages/eslint-config/src/tanstack.ts: -------------------------------------------------------------------------------- 1 | import query from '@tanstack/eslint-plugin-query'; 2 | import router from '@tanstack/eslint-plugin-router'; 3 | import type { Linter } from 'eslint'; 4 | 5 | export const tanstack: Linter.Config[] = [ 6 | ...query.configs['flat/recommended'], 7 | ...router.configs['flat/recommended'], 8 | ]; 9 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/eslint-config-turbo.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-config-turbo/flat' { 2 | // biome-ignore lint/correctness/noUnusedImports: this is correct in d.ts files 3 | import type { Linter } from 'eslint'; 4 | // biome-ignore lint/correctness/noUndeclaredVariables: false positive 5 | const config: Linter.Config[]; 6 | 7 | export = config; 8 | } 9 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/eslint-plugin-jsx-a11y.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-jsx-a11y' { 2 | import type { Linter } from 'eslint'; 3 | 4 | interface Plugin { 5 | flatConfigs: { 6 | recommended: Linter.Config; 7 | }; 8 | } 9 | 10 | const plugin: Plugin; 11 | 12 | export = plugin; 13 | } 14 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/eslint-plugin-promise.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-promise' { 2 | // biome-ignore lint/correctness/noUnusedImports: this is correct in d.ts files 3 | import type { Linter } from 'eslint'; 4 | 5 | interface PluginPromise { 6 | rules: Linter.RulesRecord; 7 | rulesConfig: Linter.RulesRecord; 8 | configs: { 9 | recommended: Linter.LegacyConfig; 10 | 'flat/recommended': Linter.Config; 11 | }; 12 | } 13 | 14 | const pluginPromise: PluginPromise; 15 | 16 | export = pluginPromise; 17 | } 18 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/eslint-plugin-react-refresh.d.ts: -------------------------------------------------------------------------------- 1 | // types exist but are wrong: https://github.com/jsx-eslint/eslint-plugin-react/pull/3840 2 | declare module 'eslint-plugin-react-refresh' { 3 | import type { Plugin } from 'eslint'; 4 | 5 | const plugin: Plugin; 6 | 7 | export = plugin; 8 | } 9 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/eslint-plugin-react.d.ts: -------------------------------------------------------------------------------- 1 | // types exist but are wrong: https://github.com/jsx-eslint/eslint-plugin-react/pull/3840 2 | declare module 'eslint-plugin-react' { 3 | // biome-ignore lint/correctness/noUnusedImports: this is correct in d.ts files 4 | import type { Linter } from 'eslint'; 5 | 6 | interface Plugin { 7 | configs: { 8 | flat: { 9 | recommended: Linter.Config; 10 | 'jsx-runtime': Linter.Config; 11 | }; 12 | }; 13 | } 14 | 15 | const plugin: Plugin; 16 | 17 | export = plugin; 18 | } 19 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/eslint-plugin-testing-library.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'eslint-plugin-testing-library' { 2 | // biome-ignore lint/correctness/noUnusedImports: this is correct in d.ts files 3 | import type { Linter } from 'eslint'; 4 | 5 | interface TestingLibraryPlugin { 6 | configs: { 7 | 'flat/react': Linter.Config; 8 | }; 9 | } 10 | 11 | const testingLibraryPlugin: TestingLibraryPlugin; 12 | 13 | export = testingLibraryPlugin; 14 | } 15 | -------------------------------------------------------------------------------- /packages/eslint-config/src/types/next__eslint-plugin-next.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@next/eslint-plugin-next' { 2 | // biome-ignore lint/correctness/noUnusedImports: this is correct in d.ts files 3 | import type { ESLint } from 'eslint'; 4 | const pluginNext: ESLint.Plugin; 5 | export = pluginNext; 6 | } 7 | -------------------------------------------------------------------------------- /packages/eslint-config/src/vitest.ts: -------------------------------------------------------------------------------- 1 | import vitestPlugin from '@vitest/eslint-plugin'; 2 | import testingLibrary from 'eslint-plugin-testing-library'; 3 | 4 | export const vitest = [ 5 | { ignores: ['coverage/'] }, 6 | { 7 | files: ['**/*.test.{js,jsx,ts,tsx}'], 8 | plugins: { vitest: vitestPlugin }, 9 | languageOptions: { 10 | parserOptions: { 11 | ecmaFeatures: { 12 | jsx: true, 13 | }, 14 | }, 15 | globals: { 16 | ...vitestPlugin.environments.env.globals, 17 | }, 18 | }, 19 | rules: { 20 | ...vitestPlugin.configs.recommended.rules, 21 | 'vitest/max-nested-describe': ['error', { max: 3 }], 22 | }, 23 | }, 24 | { 25 | files: ['**/*.test.{js,jsx,ts,tsx}'], 26 | ...testingLibrary.configs['flat/react'], 27 | }, 28 | ]; 29 | -------------------------------------------------------------------------------- /packages/eslint-config/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Base Options: */ 4 | "esModuleInterop": true, 5 | "skipLibCheck": true, 6 | "target": "es2023", 7 | "allowJs": true, 8 | "checkJs": true, 9 | "resolveJsonModule": true, 10 | "moduleDetection": "force", 11 | "isolatedModules": true, 12 | "verbatimModuleSyntax": true, 13 | 14 | /* Strictness */ 15 | "strict": true, 16 | "noUncheckedIndexedAccess": true, 17 | "noImplicitOverride": true, 18 | 19 | /* If transpiling with TypeScript: */ 20 | "module": "NodeNext", 21 | "rootDir": "src", 22 | "outDir": "dist", 23 | "sourceMap": true, 24 | 25 | /* AND if you're building for a library: */ 26 | "declaration": true, 27 | 28 | /* AND if you're building for a library in a monorepo: */ 29 | "composite": true, 30 | "declarationMap": true, 31 | 32 | /* If your code doesn't run in the DOM: */ 33 | "lib": ["es2023"] 34 | }, 35 | "include": ["src/"] 36 | } 37 | -------------------------------------------------------------------------------- /packages/eslint-config/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["//"], 3 | "tasks": { 4 | "build": { 5 | "outputs": ["dist/**"] 6 | }, 7 | "dev": { 8 | "persistent": true, 9 | "cache": false 10 | }, 11 | "lint:js": { 12 | "dependsOn": ["build"] 13 | }, 14 | "lint:ts": {} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/react/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Motif 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/react/__mocks__/zustand.ts: -------------------------------------------------------------------------------- 1 | import { act } from '@testing-library/react'; 2 | import { afterEach, vi } from 'vitest'; 3 | import type * as zustand from 'zustand'; 4 | 5 | const { 6 | create: actualCreate, 7 | createStore: actualCreateStore, 8 | useStore: actualUseStore, 9 | } = await vi.importActual('zustand'); 10 | 11 | // a variable to hold reset functions for all stores declared in the app 12 | export const storeResetFns = new Set<() => void>(); 13 | 14 | const createUncurried = ( 15 | stateCreator: zustand.StateCreator, 16 | ): zustand.UseBoundStore> => { 17 | const store = actualCreate(stateCreator); 18 | const initialState = store.getState(); 19 | storeResetFns.add(() => { 20 | store.setState(initialState, true); 21 | }); 22 | return store; 23 | }; 24 | 25 | // when creating a store, we get its initial state, create a reset function and add it in the set 26 | export const create = ((stateCreator: zustand.StateCreator) => { 27 | // to support curried version of create 28 | return typeof stateCreator === 'function' 29 | ? createUncurried(stateCreator) 30 | : createUncurried; 31 | }) as typeof zustand.create; 32 | 33 | const createStoreUncurried = ( 34 | stateCreator: zustand.StateCreator, 35 | ): zustand.StoreApi => { 36 | const store = actualCreateStore(stateCreator); 37 | const initialState = store.getState(); 38 | storeResetFns.add(() => { 39 | store.setState(initialState, true); 40 | }); 41 | return store; 42 | }; 43 | 44 | // when creating a store, we get its initial state, create a reset function and add it in the set 45 | export const createStore = ((stateCreator: zustand.StateCreator) => { 46 | // to support curried version of createStore 47 | return typeof stateCreator === 'function' 48 | ? createStoreUncurried(stateCreator) 49 | : createStoreUncurried; 50 | }) as typeof zustand.createStore; 51 | 52 | afterEach(() => { 53 | act(() => { 54 | localStorage.clear(); 55 | for (const resetFn of storeResetFns) { 56 | resetFn(); 57 | } 58 | }); 59 | }); 60 | 61 | export { actualUseStore as useStore }; 62 | -------------------------------------------------------------------------------- /packages/react/eslint.config.js: -------------------------------------------------------------------------------- 1 | import { configs } from '@markprompt/eslint-config'; 2 | 3 | export default [ 4 | ...configs.base(import.meta.dirname, [ 5 | 'eslint.config.js', 6 | 'vitest.config.ts', 7 | 'vitest.setup.ts', 8 | ]), 9 | { 10 | rules: { 11 | '@typescript-eslint/consistent-indexed-object-style': [ 12 | 'error', 13 | 'index-signature', 14 | ], 15 | }, 16 | }, 17 | ...configs.react, 18 | ...configs.vitest, 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/react/src/chat/Answer.tsx: -------------------------------------------------------------------------------- 1 | import { clsx } from 'clsx'; 2 | import type { ComponentType, JSX } from 'react'; 3 | 4 | import * as BaseMarkprompt from '../primitives/headless.js'; 5 | import type { ChatViewAssistantMessage } from '../types.js'; 6 | 7 | interface AnswerProps { 8 | /** 9 | * Custom class name. 10 | */ 11 | className?: string; 12 | /** 13 | * The message to display, in Markdown format. 14 | */ 15 | message: ChatViewAssistantMessage; 16 | /** 17 | * Component to use in place of . 18 | * @default "a" 19 | */ 20 | linkAs?: string | ComponentType; 21 | } 22 | 23 | export function Answer(props: AnswerProps): JSX.Element { 24 | const { message, className, linkAs } = props; 25 | 26 | return ( 27 |
34 | {Array.isArray(message.content) ? ( 35 | message.content.map((part, index) => ( 36 | 43 | )) 44 | ) : ( 45 | 51 | )} 52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /packages/react/src/chat/MessageAnswer.tsx: -------------------------------------------------------------------------------- 1 | import type { ComponentType, JSX } from 'react'; 2 | 3 | import { Answer } from './Answer.js'; 4 | import type { ChatViewAssistantMessage } from '../types.js'; 5 | 6 | function LoadingDots(): JSX.Element { 7 | return ( 8 |
9 | 10 | 11 | 12 |
13 | ); 14 | } 15 | 16 | interface MessageAnswerProps { 17 | message: ChatViewAssistantMessage; 18 | linkAs?: string | ComponentType; 19 | } 20 | 21 | export function MessageAnswer(props: MessageAnswerProps): JSX.Element { 22 | const { message } = props; 23 | 24 | return ( 25 |
26 | {(message.state === 'indeterminate' || message.state === 'preload') && ( 27 |
28 | 29 |
30 | )} 31 | 32 | 33 | 34 | {message.state === 'cancelled' && ( 35 |
36 |
37 | This chat response was cancelled. Please try regenerating the answer 38 | or ask another question. 39 |
40 |
41 | )} 42 |
43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /packages/react/src/chat/ThreadSelect.tsx: -------------------------------------------------------------------------------- 1 | import { getMessageTextContent } from '@markprompt/core/utils'; 2 | import type { JSX } from 'react'; 3 | 4 | import { selectProjectThreads, useChatStore } from './store.js'; 5 | import { CounterClockwiseClockIcon, PlusIcon } from '../icons.js'; 6 | import { Select } from '../primitives/Select.js'; 7 | 8 | export function ThreadSelect({ 9 | disabled, 10 | }: { 11 | disabled?: boolean; 12 | }): JSX.Element { 13 | const threads = useChatStore(selectProjectThreads); 14 | const selectThread = useChatStore((state) => state.selectThread); 15 | 16 | return ( 17 |