From b627dc653ef49bb42f841da59fded50647653eac Mon Sep 17 00:00:00 2001 From: fuegovic Date: Thu, 9 May 2024 17:09:13 -0400 Subject: [PATCH] initial commit --- .env.template | 20 + .eslintrc.cjs | 241 + .github/CODEOWNERS | 67 + .github/dependabot.yml | 29 + .github/workflows/nextjs_bundle_analysis.yml | 130 + .gitignore | 22 + .husky/pre-commit | 1 + .npmrc | 1 + .nvmrc | 1 + .prettierrc.js | 7 + LICENSE | 2 +- README.md | 19 + components.json | 15 + components/Author/AuthorPage.tsx | 88 + components/Author/AuthorProfile.tsx | 129 + components/Author/Authors.tsx | 47 + components/Author/AuthorsSmall.tsx | 41 + components/CardIcons/AboutLogo.tsx | 36 + components/CardIcons/Blog.tsx | 34 + components/CardIcons/Changelog.tsx | 34 + components/CardIcons/OurAuthors.tsx | 34 + components/CardIcons/Roadmap.tsx | 36 + components/CardIcons/ToolKit.tsx | 34 + components/FooterMenu.tsx | 165 + components/Frame.tsx | 35 + components/Header.tsx | 42 + components/LogoContextMenu.tsx | 70 + components/Newsletter/SubscribeForm.tsx | 66 + components/Newsletter/UnsubscribeForm.tsx | 66 + .../Newsletter/newsletterform.module.css | 74 + components/Tweet.tsx | 8 + components/Video.tsx | 77 + components/analytics/hubspot.tsx | 11 + components/blog/BlogCard.tsx | 93 + components/blog/BlogHeader.tsx | 70 + components/blog/BlogIndex.tsx | 195 + components/callouts/callout.tsx | 93 + components/callouts/style.module.css | 224 + components/cards.tsx | 35 + components/carousel/Carousel.tsx | 71 + components/carousel/style.module.css | 138 + components/changelog/ChangelogHeader.tsx | 70 + components/changelog/ChangelogIndex.tsx | 78 + components/feature.tsx | 31 + components/features/index.tsx | 46 + components/features/style.module.css | 142 + components/features/themes-animation.tsx | 115 + components/home/Changelog.tsx | 99 + components/home/Footer.tsx | 15 + components/home/Hero.tsx | 71 + components/home/Pricing.tsx | 575 + components/home/components/HomeSection.tsx | 21 + components/home/feature.module.css | 150 + components/home/feature.tsx | 89 + components/home/hero.module.css | 404 + components/home/index.tsx | 13 + components/icons/README.md | 7 + components/icons/discord.tsx | 21 + components/icons/github.tsx | 18 + components/lcLogo/index.tsx | 89 + components/lcLogo/style.module.css | 11 + components/logo.tsx | 46 + components/magicui/bento-grid.tsx | 62 + components/magicui/border-beam.tsx | 49 + components/magicui/grid-pattern.tsx | 58 + components/magicui/linear-gradient.tsx | 82 + components/magicui/marquee.tsx | 51 + components/magicui/meteors.tsx | 39 + components/magicui/retro-grid.tsx | 27 + components/magicui/shimmer-button.tsx | 62 + components/mobileSwitch.tsx | 31 + components/policies.tsx | 130 + components/screenshot.tsx | 21 + components/supportChat/chat.tsx | 21 + components/supportChat/index.tsx | 7 + components/svg/ArrowRight.tsx | 15 + components/svg/ArrowUp.tsx | 11 + components/svg/Box.tsx | 15 + components/svg/Brush.tsx | 15 + components/svg/Cards.tsx | 15 + components/svg/ChevronRight.tsx | 11 + components/svg/Close.tsx | 11 + components/svg/Cloud.tsx | 15 + components/svg/Code.tsx | 15 + components/svg/Diagram.tsx | 11 + components/svg/DockerIcon.tsx | 19 + components/svg/Dropper.tsx | 15 + components/svg/File.tsx | 15 + components/svg/Files.tsx | 15 + components/svg/FolderTree.tsx | 11 + components/svg/Formula.tsx | 15 + components/svg/Gear.tsx | 15 + components/svg/Globe.tsx | 15 + components/svg/IdCard.tsx | 16 + components/svg/Lightning.tsx | 15 + components/svg/Link.tsx | 15 + components/svg/Markdown.tsx | 14 + components/svg/Newsletter.tsx | 15 + components/svg/NpmIcon.tsx | 12 + components/svg/One.tsx | 11 + components/svg/Picture.tsx | 15 + components/svg/Rows.tsx | 15 + components/svg/Search.tsx | 21 + components/svg/Sort.tsx | 11 + components/svg/Stars.tsx | 15 + components/svg/Switch.tsx | 14 + components/svg/Table.tsx | 15 + components/svg/Terminal.tsx | 30 + components/svg/Warning.tsx | 15 + components/svg/index.tsx | 34 + components/table/index.tsx | 38 + components/table/style.module.css | 13 + components/tools/CredentialsGeneratorBox.tsx | 178 + components/tools/credentialsGenerator.ts | 32 + components/tools/yamlChecker.tsx | 130 + components/ui/accordion.tsx | 61 + components/ui/avatar.tsx | 47 + components/ui/button.tsx | 55 + components/ui/card.tsx | 58 + components/ui/dialog.tsx | 99 + components/ui/dropdown-menu.tsx | 185 + components/ui/form.tsx | 167 + components/ui/input.tsx | 24 + components/ui/label.tsx | 21 + components/ui/select.tsx | 166 + components/ui/table.tsx | 91 + components/ui/tabs.tsx | 57 + components/ui/textarea.tsx | 23 + global.d.ts | 3 + lib/fonts/Geist-Regular.ttf | Bin 0 -> 107600 bytes lib/fonts/GeistMono-Medium.ttf | Bin 0 -> 115592 bytes lib/fonts/Readme.md | 3 + lib/utils.ts | 6 + next-env.d.ts | 5 + next-sitemap.config.js | 17 + next.config.mjs | 134 + package.json | 117 + pages/404.mdx | 9 + pages/README.md | 26 + pages/_app.tsx | 56 + pages/_meta.ts | 100 + pages/about.mdx | 170 + pages/api/subscribe.ts | 35 + pages/api/unsubscribe.ts | 37 + pages/authors/_meta.ts | 13 + pages/authors/anon.mdx | 14 + pages/authors/berry.mdx | 17 + pages/authors/danny.mdx | 17 + pages/authors/fuegovic.mdx | 17 + pages/authors/index.mdx | 15 + pages/authors/librechat.mdx | 20 + pages/blog.mdx | 15 + pages/blog/2023-08-18_podman.mdx | 277 + pages/blog/2023-10-29_basic_auth.mdx | 79 + pages/blog/2023-11-30_litellm.mdx | 411 + pages/blog/2023-11-30_mongoexpress.mdx | 91 + pages/blog/2024-02-19_2024_roadmap.mdx | 74 + pages/blog/2024-03-02_ollama.mdx | 93 + pages/blog/2024-03-22_unraid_guide.mdx | 104 + pages/blog/2024-04-17_blog_guide.mdx | 101 + pages/blog/2024-05-01_mlx.mdx | 47 + pages/blog/_meta.ts | 12 + pages/changelog.mdx | 22 + pages/changelog/_meta.ts | 8 + pages/changelog/config_v1.0.0.mdx | 37 + pages/changelog/config_v1.01.mdx | 12 + pages/changelog/config_v1.02.mdx | 14 + pages/changelog/config_v1.03.mdx | 16 + pages/changelog/config_v1.04.mdx | 12 + pages/changelog/config_v1.05.mdx | 15 + pages/changelog/config_v1.06.mdx | 13 + pages/changelog/config_v1.07.mdx | 13 + pages/changelog/config_v1.08.mdx | 21 + pages/changelog/config_v1.09.mdx | 13 + pages/changelog/v0.5.0.mdx | 75 + pages/changelog/v0.5.1.mdx | 56 + pages/changelog/v0.5.2.mdx | 52 + pages/changelog/v0.5.3.mdx | 51 + pages/changelog/v0.5.4.mdx | 54 + pages/changelog/v0.5.5.mdx | 36 + pages/changelog/v0.5.6.mdx | 66 + pages/changelog/v0.5.7.mdx | 62 + pages/changelog/v0.5.8.mdx | 75 + pages/changelog/v0.5.9.mdx | 88 + pages/changelog/v0.6.0-breaking-changes.mdx | 18 + pages/changelog/v0.6.0.mdx | 78 + pages/changelog/v0.6.1.mdx | 53 + pages/changelog/v0.6.10-breaking-changes.mdx | 65 + pages/changelog/v0.6.10.mdx | 51 + pages/changelog/v0.6.5.mdx | 57 + pages/changelog/v0.6.6.mdx | 136 + pages/changelog/v0.6.9-breaking-changes.mdx | 72 + pages/changelog/v0.6.9.mdx | 127 + pages/changelog/v0.7.0-breaking-changes.mdx | 145 + pages/changelog/v0.7.0.mdx | 197 + pages/changelog/v0.7.1.mdx | 124 + pages/cookie.mdx | 129 + pages/demo.mdx | 3 + pages/docs/_meta.ts | 17 + pages/docs/configuration/_meta.ts | 8 + .../authentication/OAuth2-OIDC/_meta.ts | 16 + .../authentication/OAuth2-OIDC/aws.mdx | 113 + .../authentication/OAuth2-OIDC/azure.mdx | 58 + .../authentication/OAuth2-OIDC/discord.mdx | 48 + .../authentication/OAuth2-OIDC/facebook.mdx | 82 + .../authentication/OAuth2-OIDC/github.mdx | 64 + .../authentication/OAuth2-OIDC/google.mdx | 96 + .../authentication/OAuth2-OIDC/index.mdx | 28 + .../authentication/OAuth2-OIDC/keycloak.mdx | 67 + .../configuration/authentication/_meta.ts | 3 + .../configuration/authentication/index.mdx | 96 + .../authentication/password_reset.mdx | 81 + pages/docs/configuration/docker_override.mdx | 102 + pages/docs/configuration/dotenv.mdx | 885 ++ pages/docs/configuration/firebase.mdx | 116 + pages/docs/configuration/index.mdx | 18 + .../configuration/librechat_yaml/_meta.ts | 7 + .../librechat_yaml/ai_endpoints/_meta.ts | 3 + .../librechat_yaml/ai_endpoints/anyscale.mdx | 31 + .../librechat_yaml/ai_endpoints/apipie.mdx | 87 + .../librechat_yaml/ai_endpoints/azure.mdx | 570 + .../librechat_yaml/ai_endpoints/cohere.mdx | 37 + .../librechat_yaml/ai_endpoints/fireworks.mdx | 33 + .../librechat_yaml/ai_endpoints/groq.mdx | 36 + .../librechat_yaml/ai_endpoints/index.mdx | 14 + .../librechat_yaml/ai_endpoints/litellm.mdx | 28 + .../librechat_yaml/ai_endpoints/mistral.mdx | 34 + .../librechat_yaml/ai_endpoints/mlx.mdx | 37 + .../librechat_yaml/ai_endpoints/ollama.mdx | 97 + .../ai_endpoints/openrouter.mdx | 35 + .../ai_endpoints/perplexity.mdx | 39 + .../librechat_yaml/ai_endpoints/shuttleai.mdx | 32 + .../ai_endpoints/togetherai.mdx | 74 + .../configuration/librechat_yaml/example.mdx | 424 + .../configuration/librechat_yaml/index.mdx | 36 + .../librechat_yaml/object_structure/_meta.ts | 12 + .../object_structure/assistants_endpoint.mdx | 139 + .../object_structure/azure_openai.mdx | 276 + .../object_structure/config.mdx | 222 + .../object_structure/custom_endpoint.mdx | 348 + .../object_structure/default_params.mdx | 33 + .../object_structure/file_config.mdx | 184 + .../object_structure/interface.mdx | 157 + .../object_structure/model_config.mdx | 66 + .../object_structure/model_specs.mdx | 293 + .../object_structure/registration.mdx | 45 + .../configuration/librechat_yaml/setup.mdx | 39 + pages/docs/configuration/logging.mdx | 77 + pages/docs/configuration/meilisearch.mdx | 61 + pages/docs/configuration/mod_system.mdx | 109 + .../configuration/mongodb/mongodb_atlas.mdx | 64 + .../configuration/mongodb/mongodb_auth.mdx | 364 + .../mongodb/mongodb_community.mdx | 67 + .../configuration/pre_configured_ai/_meta.ts | 3 + .../pre_configured_ai/anthropic.mdx | 15 + .../pre_configured_ai/assistants.mdx | 42 + .../pre_configured_ai/google.mdx | 118 + .../configuration/pre_configured_ai/index.mdx | 27 + .../pre_configured_ai/openai.mdx | 24 + pages/docs/configuration/rag_api.mdx | 101 + pages/docs/configuration/token_usage.mdx | 104 + pages/docs/configuration/tools/_meta.ts | 3 + .../configuration/tools/azure_ai_search.mdx | 143 + .../configuration/tools/google_search.mdx | 65 + pages/docs/configuration/tools/index.mdx | 43 + .../configuration/tools/stable_diffusion.mdx | 76 + pages/docs/configuration/tools/wolfram.mdx | 31 + pages/docs/development/_meta.ts | 26 + pages/docs/development/architecture.mdx | 8 + pages/docs/development/conventions.mdx | 109 + pages/docs/development/debugging.mdx | 10 + pages/docs/development/get_started.mdx | 185 + pages/docs/development/index.mdx | 22 + pages/docs/development/testing.mdx | 25 + pages/docs/development/tools_and_plugins.mdx | 349 + pages/docs/development/translation.mdx | 128 + pages/docs/documentation/_meta.ts | 5 + pages/docs/documentation/examples.mdx | 838 ++ pages/docs/documentation/index.mdx | 134 + .../documentation/syntax_highlighting.mdx | 473 + pages/docs/index.mdx | 46 + pages/docs/local/_meta.ts | 5 + pages/docs/local/docker.mdx | 80 + pages/docs/local/index.mdx | 27 + pages/docs/local/npm.mdx | 107 + pages/docs/remote/_meta.ts | 15 + pages/docs/remote/cloudflare.mdx | 73 + pages/docs/remote/digitalocean.mdx | 126 + pages/docs/remote/docker_linux.mdx | 438 + pages/docs/remote/huggingface.mdx | 91 + pages/docs/remote/index.mdx | 148 + pages/docs/remote/nginx.mdx | 137 + pages/docs/remote/ngrok.mdx | 51 + pages/docs/remote/railway.mdx | 54 + pages/docs/remote/traefik.mdx | 92 + pages/docs/user_guides/_meta.ts | 3 + pages/docs/user_guides/ai_overview.mdx | 30 + pages/docs/user_guides/authentication.mdx | 30 + pages/docs/user_guides/fork.mdx | 117 + pages/docs/user_guides/import_convos.mdx | 36 + pages/docs/user_guides/index.mdx | 20 + pages/docs/user_guides/mod_system.mdx | 36 + pages/docs/user_guides/mongodb.mdx | 43 + pages/docs/user_guides/password_reset.mdx | 27 + pages/docs/user_guides/plugins.mdx | 55 + pages/docs/user_guides/presets.mdx | 91 + pages/docs/user_guides/rag_api.mdx | 73 + pages/docs/user_guides/search.mdx | 18 + pages/index.mdx | 8 + pages/pricing.mdx | 7 + pages/privacy.mdx | 823 ++ pages/subscribe.mdx | 7 + pages/toolkit/_meta.ts | 5 + pages/toolkit/creds_generator.mdx | 3 + pages/toolkit/index.mdx | 18 + pages/toolkit/yaml_checker.mdx | 7 + pages/tos.mdx | 7 + pages/unsubscribe.mdx | 7 + pnpm-lock.yaml | 9986 +++++++++++++++++ postcss.config.js | 6 + public/android-chrome-192x192.png | Bin 0 -> 23036 bytes public/android-chrome-512x512.png | Bin 0 -> 78550 bytes public/apple-touch-icon.png | Bin 0 -> 20672 bytes public/browserconfig.xml | 9 + public/favicon-16x16.png | Bin 0 -> 785 bytes public/favicon-32x32.png | Bin 0 -> 1818 bytes public/favicon.ico | Bin 0 -> 15406 bytes public/favicon.png | Bin 0 -> 108602 bytes public/images/blog/2023-08-18_podman.png | Bin 0 -> 233901 bytes public/images/blog/2023-10-29_basic_auth.png | Bin 0 -> 2017130 bytes public/images/blog/2023-11-30_litellm.png | Bin 0 -> 2048187 bytes .../images/blog/2023-11-30_mongoexpress.png | Bin 0 -> 1541320 bytes .../images/blog/2024-02-19_2024_roadmap.webp | Bin 0 -> 74666 bytes public/images/blog/2024-03-02_ollama.png | Bin 0 -> 29681 bytes .../images/blog/2024-03-22_unraid_guide.png | Bin 0 -> 723535 bytes public/images/blog/2024-04-17_blog_guide.png | Bin 0 -> 1394799 bytes public/images/blog/2024-05-01_mlx.png | Bin 0 -> 54402 bytes public/images/cards/article.svg | 26 + public/images/cards/code.svg | 135 + public/images/cards/config.svg | 121 + public/images/cards/docs.svg | 135 + public/images/cards/guides.svg | 135 + public/images/cards/local.svg | 105 + public/images/cards/profile.svg | 6 + public/images/cards/remote.svg | 105 + public/images/cards/route.svg | 28 + public/images/cards/shooting-star.svg | 13 + public/images/cards/toolbox.svg | 89 + public/images/changelog/v0.5.0.png | Bin 0 -> 1317933 bytes public/images/changelog/v0.6.0.png | Bin 0 -> 1641411 bytes public/images/changelog/v0.7.0.png | Bin 0 -> 803055 bytes public/images/changelog/v0.7.1.webp | Bin 0 -> 9484 bytes public/images/people/anon.png | Bin 0 -> 19388 bytes public/images/people/berry.png | Bin 0 -> 258006 bytes public/images/people/danny.webp | Bin 0 -> 17032 bytes public/images/people/fuegovic.png | Bin 0 -> 410258 bytes public/images/people/librechat.png | Bin 0 -> 2258874 bytes .../images/socialcards/default-blog-image.png | Bin 0 -> 3505577 bytes .../socialcards/default-changelog-image.png | Bin 0 -> 3505577 bytes .../images/socialcards/default-docs-image.png | Bin 0 -> 3505577 bytes public/images/socialcards/default-image.png | Bin 0 -> 3505577 bytes public/librechat.png | Bin 0 -> 59599 bytes public/librechat.svg | 34 + public/librechat_alt.png | Bin 0 -> 148350 bytes public/librechat_alt.svg | 30 + public/mstile-144x144.png | Bin 0 -> 11543 bytes public/mstile-150x150.png | Bin 0 -> 10797 bytes public/mstile-310x150.png | Bin 0 -> 11533 bytes public/mstile-310x310.png | Bin 0 -> 28176 bytes public/mstile-70x70.png | Bin 0 -> 7007 bytes public/safari-pinned-tab.svg | 46 + public/site.webmanifest | 19 + public/videos/example.mp4 | Bin 0 -> 443348 bytes scripts/clean-cache.ts | 17 + src/overrides.css | 74 + style.css | 116 + tailwind.config.js | 150 + theme.config.tsx | 129 + tsconfig.json | 34 + types/config.ts | 67 + types/index.ts | 1 + utils/Subscriber.js | 18 + utils/dbConnect.js | 25 + 383 files changed, 35369 insertions(+), 1 deletion(-) create mode 100644 .env.template create mode 100644 .eslintrc.cjs create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/nextjs_bundle_analysis.yml create mode 100644 .gitignore create mode 100644 .husky/pre-commit create mode 100644 .npmrc create mode 100644 .nvmrc create mode 100644 .prettierrc.js create mode 100644 README.md create mode 100644 components.json create mode 100644 components/Author/AuthorPage.tsx create mode 100644 components/Author/AuthorProfile.tsx create mode 100644 components/Author/Authors.tsx create mode 100644 components/Author/AuthorsSmall.tsx create mode 100644 components/CardIcons/AboutLogo.tsx create mode 100644 components/CardIcons/Blog.tsx create mode 100644 components/CardIcons/Changelog.tsx create mode 100644 components/CardIcons/OurAuthors.tsx create mode 100644 components/CardIcons/Roadmap.tsx create mode 100644 components/CardIcons/ToolKit.tsx create mode 100644 components/FooterMenu.tsx create mode 100644 components/Frame.tsx create mode 100644 components/Header.tsx create mode 100644 components/LogoContextMenu.tsx create mode 100644 components/Newsletter/SubscribeForm.tsx create mode 100644 components/Newsletter/UnsubscribeForm.tsx create mode 100644 components/Newsletter/newsletterform.module.css create mode 100644 components/Tweet.tsx create mode 100644 components/Video.tsx create mode 100644 components/analytics/hubspot.tsx create mode 100644 components/blog/BlogCard.tsx create mode 100644 components/blog/BlogHeader.tsx create mode 100644 components/blog/BlogIndex.tsx create mode 100644 components/callouts/callout.tsx create mode 100644 components/callouts/style.module.css create mode 100644 components/cards.tsx create mode 100644 components/carousel/Carousel.tsx create mode 100644 components/carousel/style.module.css create mode 100644 components/changelog/ChangelogHeader.tsx create mode 100644 components/changelog/ChangelogIndex.tsx create mode 100644 components/feature.tsx create mode 100644 components/features/index.tsx create mode 100644 components/features/style.module.css create mode 100644 components/features/themes-animation.tsx create mode 100644 components/home/Changelog.tsx create mode 100644 components/home/Footer.tsx create mode 100644 components/home/Hero.tsx create mode 100644 components/home/Pricing.tsx create mode 100644 components/home/components/HomeSection.tsx create mode 100644 components/home/feature.module.css create mode 100644 components/home/feature.tsx create mode 100644 components/home/hero.module.css create mode 100644 components/home/index.tsx create mode 100644 components/icons/README.md create mode 100644 components/icons/discord.tsx create mode 100644 components/icons/github.tsx create mode 100644 components/lcLogo/index.tsx create mode 100644 components/lcLogo/style.module.css create mode 100644 components/logo.tsx create mode 100644 components/magicui/bento-grid.tsx create mode 100644 components/magicui/border-beam.tsx create mode 100644 components/magicui/grid-pattern.tsx create mode 100644 components/magicui/linear-gradient.tsx create mode 100644 components/magicui/marquee.tsx create mode 100644 components/magicui/meteors.tsx create mode 100644 components/magicui/retro-grid.tsx create mode 100644 components/magicui/shimmer-button.tsx create mode 100644 components/mobileSwitch.tsx create mode 100644 components/policies.tsx create mode 100644 components/screenshot.tsx create mode 100644 components/supportChat/chat.tsx create mode 100644 components/supportChat/index.tsx create mode 100644 components/svg/ArrowRight.tsx create mode 100644 components/svg/ArrowUp.tsx create mode 100644 components/svg/Box.tsx create mode 100644 components/svg/Brush.tsx create mode 100644 components/svg/Cards.tsx create mode 100644 components/svg/ChevronRight.tsx create mode 100644 components/svg/Close.tsx create mode 100644 components/svg/Cloud.tsx create mode 100644 components/svg/Code.tsx create mode 100644 components/svg/Diagram.tsx create mode 100644 components/svg/DockerIcon.tsx create mode 100644 components/svg/Dropper.tsx create mode 100644 components/svg/File.tsx create mode 100644 components/svg/Files.tsx create mode 100644 components/svg/FolderTree.tsx create mode 100644 components/svg/Formula.tsx create mode 100644 components/svg/Gear.tsx create mode 100644 components/svg/Globe.tsx create mode 100644 components/svg/IdCard.tsx create mode 100644 components/svg/Lightning.tsx create mode 100644 components/svg/Link.tsx create mode 100644 components/svg/Markdown.tsx create mode 100644 components/svg/Newsletter.tsx create mode 100644 components/svg/NpmIcon.tsx create mode 100644 components/svg/One.tsx create mode 100644 components/svg/Picture.tsx create mode 100644 components/svg/Rows.tsx create mode 100644 components/svg/Search.tsx create mode 100644 components/svg/Sort.tsx create mode 100644 components/svg/Stars.tsx create mode 100644 components/svg/Switch.tsx create mode 100644 components/svg/Table.tsx create mode 100644 components/svg/Terminal.tsx create mode 100644 components/svg/Warning.tsx create mode 100644 components/svg/index.tsx create mode 100644 components/table/index.tsx create mode 100644 components/table/style.module.css create mode 100644 components/tools/CredentialsGeneratorBox.tsx create mode 100644 components/tools/credentialsGenerator.ts create mode 100644 components/tools/yamlChecker.tsx create mode 100644 components/ui/accordion.tsx create mode 100644 components/ui/avatar.tsx create mode 100644 components/ui/button.tsx create mode 100644 components/ui/card.tsx create mode 100644 components/ui/dialog.tsx create mode 100644 components/ui/dropdown-menu.tsx create mode 100644 components/ui/form.tsx create mode 100644 components/ui/input.tsx create mode 100644 components/ui/label.tsx create mode 100644 components/ui/select.tsx create mode 100644 components/ui/table.tsx create mode 100644 components/ui/tabs.tsx create mode 100644 components/ui/textarea.tsx create mode 100644 global.d.ts create mode 100644 lib/fonts/Geist-Regular.ttf create mode 100644 lib/fonts/GeistMono-Medium.ttf create mode 100644 lib/fonts/Readme.md create mode 100644 lib/utils.ts create mode 100644 next-env.d.ts create mode 100644 next-sitemap.config.js create mode 100644 next.config.mjs create mode 100644 package.json create mode 100644 pages/404.mdx create mode 100644 pages/README.md create mode 100644 pages/_app.tsx create mode 100644 pages/_meta.ts create mode 100644 pages/about.mdx create mode 100644 pages/api/subscribe.ts create mode 100644 pages/api/unsubscribe.ts create mode 100644 pages/authors/_meta.ts create mode 100644 pages/authors/anon.mdx create mode 100644 pages/authors/berry.mdx create mode 100644 pages/authors/danny.mdx create mode 100644 pages/authors/fuegovic.mdx create mode 100644 pages/authors/index.mdx create mode 100644 pages/authors/librechat.mdx create mode 100644 pages/blog.mdx create mode 100644 pages/blog/2023-08-18_podman.mdx create mode 100644 pages/blog/2023-10-29_basic_auth.mdx create mode 100644 pages/blog/2023-11-30_litellm.mdx create mode 100644 pages/blog/2023-11-30_mongoexpress.mdx create mode 100644 pages/blog/2024-02-19_2024_roadmap.mdx create mode 100644 pages/blog/2024-03-02_ollama.mdx create mode 100644 pages/blog/2024-03-22_unraid_guide.mdx create mode 100644 pages/blog/2024-04-17_blog_guide.mdx create mode 100644 pages/blog/2024-05-01_mlx.mdx create mode 100644 pages/blog/_meta.ts create mode 100644 pages/changelog.mdx create mode 100644 pages/changelog/_meta.ts create mode 100644 pages/changelog/config_v1.0.0.mdx create mode 100644 pages/changelog/config_v1.01.mdx create mode 100644 pages/changelog/config_v1.02.mdx create mode 100644 pages/changelog/config_v1.03.mdx create mode 100644 pages/changelog/config_v1.04.mdx create mode 100644 pages/changelog/config_v1.05.mdx create mode 100644 pages/changelog/config_v1.06.mdx create mode 100644 pages/changelog/config_v1.07.mdx create mode 100644 pages/changelog/config_v1.08.mdx create mode 100644 pages/changelog/config_v1.09.mdx create mode 100644 pages/changelog/v0.5.0.mdx create mode 100644 pages/changelog/v0.5.1.mdx create mode 100644 pages/changelog/v0.5.2.mdx create mode 100644 pages/changelog/v0.5.3.mdx create mode 100644 pages/changelog/v0.5.4.mdx create mode 100644 pages/changelog/v0.5.5.mdx create mode 100644 pages/changelog/v0.5.6.mdx create mode 100644 pages/changelog/v0.5.7.mdx create mode 100644 pages/changelog/v0.5.8.mdx create mode 100644 pages/changelog/v0.5.9.mdx create mode 100644 pages/changelog/v0.6.0-breaking-changes.mdx create mode 100644 pages/changelog/v0.6.0.mdx create mode 100644 pages/changelog/v0.6.1.mdx create mode 100644 pages/changelog/v0.6.10-breaking-changes.mdx create mode 100644 pages/changelog/v0.6.10.mdx create mode 100644 pages/changelog/v0.6.5.mdx create mode 100644 pages/changelog/v0.6.6.mdx create mode 100644 pages/changelog/v0.6.9-breaking-changes.mdx create mode 100644 pages/changelog/v0.6.9.mdx create mode 100644 pages/changelog/v0.7.0-breaking-changes.mdx create mode 100644 pages/changelog/v0.7.0.mdx create mode 100644 pages/changelog/v0.7.1.mdx create mode 100644 pages/cookie.mdx create mode 100644 pages/demo.mdx create mode 100644 pages/docs/_meta.ts create mode 100644 pages/docs/configuration/_meta.ts create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/_meta.ts create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/aws.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/azure.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/discord.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/facebook.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/github.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/google.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/index.mdx create mode 100644 pages/docs/configuration/authentication/OAuth2-OIDC/keycloak.mdx create mode 100644 pages/docs/configuration/authentication/_meta.ts create mode 100644 pages/docs/configuration/authentication/index.mdx create mode 100644 pages/docs/configuration/authentication/password_reset.mdx create mode 100644 pages/docs/configuration/docker_override.mdx create mode 100644 pages/docs/configuration/dotenv.mdx create mode 100644 pages/docs/configuration/firebase.mdx create mode 100644 pages/docs/configuration/index.mdx create mode 100644 pages/docs/configuration/librechat_yaml/_meta.ts create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/_meta.ts create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/anyscale.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/apipie.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/azure.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/cohere.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/fireworks.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/groq.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/index.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/litellm.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/mistral.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/mlx.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/ollama.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/openrouter.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/perplexity.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/shuttleai.mdx create mode 100644 pages/docs/configuration/librechat_yaml/ai_endpoints/togetherai.mdx create mode 100644 pages/docs/configuration/librechat_yaml/example.mdx create mode 100644 pages/docs/configuration/librechat_yaml/index.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/_meta.ts create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/assistants_endpoint.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/azure_openai.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/config.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/custom_endpoint.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/default_params.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/file_config.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/interface.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/model_config.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/model_specs.mdx create mode 100644 pages/docs/configuration/librechat_yaml/object_structure/registration.mdx create mode 100644 pages/docs/configuration/librechat_yaml/setup.mdx create mode 100644 pages/docs/configuration/logging.mdx create mode 100644 pages/docs/configuration/meilisearch.mdx create mode 100644 pages/docs/configuration/mod_system.mdx create mode 100644 pages/docs/configuration/mongodb/mongodb_atlas.mdx create mode 100644 pages/docs/configuration/mongodb/mongodb_auth.mdx create mode 100644 pages/docs/configuration/mongodb/mongodb_community.mdx create mode 100644 pages/docs/configuration/pre_configured_ai/_meta.ts create mode 100644 pages/docs/configuration/pre_configured_ai/anthropic.mdx create mode 100644 pages/docs/configuration/pre_configured_ai/assistants.mdx create mode 100644 pages/docs/configuration/pre_configured_ai/google.mdx create mode 100644 pages/docs/configuration/pre_configured_ai/index.mdx create mode 100644 pages/docs/configuration/pre_configured_ai/openai.mdx create mode 100644 pages/docs/configuration/rag_api.mdx create mode 100644 pages/docs/configuration/token_usage.mdx create mode 100644 pages/docs/configuration/tools/_meta.ts create mode 100644 pages/docs/configuration/tools/azure_ai_search.mdx create mode 100644 pages/docs/configuration/tools/google_search.mdx create mode 100644 pages/docs/configuration/tools/index.mdx create mode 100644 pages/docs/configuration/tools/stable_diffusion.mdx create mode 100644 pages/docs/configuration/tools/wolfram.mdx create mode 100644 pages/docs/development/_meta.ts create mode 100644 pages/docs/development/architecture.mdx create mode 100644 pages/docs/development/conventions.mdx create mode 100644 pages/docs/development/debugging.mdx create mode 100644 pages/docs/development/get_started.mdx create mode 100644 pages/docs/development/index.mdx create mode 100644 pages/docs/development/testing.mdx create mode 100644 pages/docs/development/tools_and_plugins.mdx create mode 100644 pages/docs/development/translation.mdx create mode 100644 pages/docs/documentation/_meta.ts create mode 100644 pages/docs/documentation/examples.mdx create mode 100644 pages/docs/documentation/index.mdx create mode 100644 pages/docs/documentation/syntax_highlighting.mdx create mode 100644 pages/docs/index.mdx create mode 100644 pages/docs/local/_meta.ts create mode 100644 pages/docs/local/docker.mdx create mode 100644 pages/docs/local/index.mdx create mode 100644 pages/docs/local/npm.mdx create mode 100644 pages/docs/remote/_meta.ts create mode 100644 pages/docs/remote/cloudflare.mdx create mode 100644 pages/docs/remote/digitalocean.mdx create mode 100644 pages/docs/remote/docker_linux.mdx create mode 100644 pages/docs/remote/huggingface.mdx create mode 100644 pages/docs/remote/index.mdx create mode 100644 pages/docs/remote/nginx.mdx create mode 100644 pages/docs/remote/ngrok.mdx create mode 100644 pages/docs/remote/railway.mdx create mode 100644 pages/docs/remote/traefik.mdx create mode 100644 pages/docs/user_guides/_meta.ts create mode 100644 pages/docs/user_guides/ai_overview.mdx create mode 100644 pages/docs/user_guides/authentication.mdx create mode 100644 pages/docs/user_guides/fork.mdx create mode 100644 pages/docs/user_guides/import_convos.mdx create mode 100644 pages/docs/user_guides/index.mdx create mode 100644 pages/docs/user_guides/mod_system.mdx create mode 100644 pages/docs/user_guides/mongodb.mdx create mode 100644 pages/docs/user_guides/password_reset.mdx create mode 100644 pages/docs/user_guides/plugins.mdx create mode 100644 pages/docs/user_guides/presets.mdx create mode 100644 pages/docs/user_guides/rag_api.mdx create mode 100644 pages/docs/user_guides/search.mdx create mode 100644 pages/index.mdx create mode 100644 pages/pricing.mdx create mode 100644 pages/privacy.mdx create mode 100644 pages/subscribe.mdx create mode 100644 pages/toolkit/_meta.ts create mode 100644 pages/toolkit/creds_generator.mdx create mode 100644 pages/toolkit/index.mdx create mode 100644 pages/toolkit/yaml_checker.mdx create mode 100644 pages/tos.mdx create mode 100644 pages/unsubscribe.mdx create mode 100644 pnpm-lock.yaml create mode 100644 postcss.config.js create mode 100644 public/android-chrome-192x192.png create mode 100644 public/android-chrome-512x512.png create mode 100644 public/apple-touch-icon.png create mode 100644 public/browserconfig.xml create mode 100644 public/favicon-16x16.png create mode 100644 public/favicon-32x32.png create mode 100644 public/favicon.ico create mode 100644 public/favicon.png create mode 100644 public/images/blog/2023-08-18_podman.png create mode 100644 public/images/blog/2023-10-29_basic_auth.png create mode 100644 public/images/blog/2023-11-30_litellm.png create mode 100644 public/images/blog/2023-11-30_mongoexpress.png create mode 100644 public/images/blog/2024-02-19_2024_roadmap.webp create mode 100644 public/images/blog/2024-03-02_ollama.png create mode 100644 public/images/blog/2024-03-22_unraid_guide.png create mode 100644 public/images/blog/2024-04-17_blog_guide.png create mode 100644 public/images/blog/2024-05-01_mlx.png create mode 100644 public/images/cards/article.svg create mode 100644 public/images/cards/code.svg create mode 100644 public/images/cards/config.svg create mode 100644 public/images/cards/docs.svg create mode 100644 public/images/cards/guides.svg create mode 100644 public/images/cards/local.svg create mode 100644 public/images/cards/profile.svg create mode 100644 public/images/cards/remote.svg create mode 100644 public/images/cards/route.svg create mode 100644 public/images/cards/shooting-star.svg create mode 100644 public/images/cards/toolbox.svg create mode 100644 public/images/changelog/v0.5.0.png create mode 100644 public/images/changelog/v0.6.0.png create mode 100644 public/images/changelog/v0.7.0.png create mode 100644 public/images/changelog/v0.7.1.webp create mode 100644 public/images/people/anon.png create mode 100644 public/images/people/berry.png create mode 100644 public/images/people/danny.webp create mode 100644 public/images/people/fuegovic.png create mode 100644 public/images/people/librechat.png create mode 100644 public/images/socialcards/default-blog-image.png create mode 100644 public/images/socialcards/default-changelog-image.png create mode 100644 public/images/socialcards/default-docs-image.png create mode 100644 public/images/socialcards/default-image.png create mode 100644 public/librechat.png create mode 100644 public/librechat.svg create mode 100644 public/librechat_alt.png create mode 100644 public/librechat_alt.svg create mode 100644 public/mstile-144x144.png create mode 100644 public/mstile-150x150.png create mode 100644 public/mstile-310x150.png create mode 100644 public/mstile-310x310.png create mode 100644 public/mstile-70x70.png create mode 100644 public/safari-pinned-tab.svg create mode 100644 public/site.webmanifest create mode 100644 public/videos/example.mp4 create mode 100644 scripts/clean-cache.ts create mode 100644 src/overrides.css create mode 100644 style.css create mode 100644 tailwind.config.js create mode 100644 theme.config.tsx create mode 100644 tsconfig.json create mode 100644 types/config.ts create mode 100644 types/index.ts create mode 100644 utils/Subscriber.js create mode 100644 utils/dbConnect.js diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..2183fe4 --- /dev/null +++ b/.env.template @@ -0,0 +1,20 @@ +# Analytics and feedback +SLACK_WEBHOOK_URL= +LOOPS_API_KEY= +NEXT_PUBLIC_POSTHOG_HOST= +NEXT_PUBLIC_POSTHOG_KEY= + +# Crisp +EXT_PUBLIC_CRISP_WEBSITE_ID= +NEXT_PUBLIC_CRISP_WEBSITE_ID= + +# For qa chatbot +OPENAI_API_KEY= +SUPABASE_URL= +SUPABASE_SERVICE_ROLE_KEY= +NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY= +LANGFUSE_PUBLIC_KEY= +LANGFUSE_SECRET_KEY= + +# Newsletter Subscribers +MONGODB_URI= \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..f86e55c --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,241 @@ +const TAILWIND_CONFIG = { + extends: ['plugin:tailwindcss/recommended'], + rules: { + 'tailwindcss/classnames-order': 'off', // conflicts with prettier-plugin-tailwindcss + 'tailwindcss/enforces-negative-arbitrary-values': 'error', + 'tailwindcss/enforces-shorthand': 'error', + 'tailwindcss/migration-from-tailwind-2': 'error', + 'tailwindcss/no-custom-classname': 'error', + }, +} + +/** @type {import('eslint').Linter.Config} */ +module.exports = { + root: true, + reportUnusedDisableDirectives: true, + ignorePatterns: ['next-env.d.ts'], + overrides: [ + // Rules for all files + { + files: '**/*.{js,jsx,cjs,mjs,ts,tsx,cts,mts}', + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/typescript', + 'prettier', + ], + plugins: ['import', 'unicorn'], + rules: { + 'prefer-object-has-own': 'error', + 'logical-assignment-operators': ['error', 'always', { enforceForIfStatements: true }], + 'no-else-return': ['error', { allowElseIf: false }], + 'no-lonely-if': 'error', + 'prefer-destructuring': ['error', { VariableDeclarator: { object: true } }], + 'import/no-duplicates': 'error', + 'no-negated-condition': 'off', + 'unicorn/no-negated-condition': 'error', + 'prefer-regex-literals': ['error', { disallowRedundantWrapping: true }], + 'object-shorthand': ['error', 'always'], + 'unicorn/prefer-regexp-test': 'error', + 'unicorn/no-array-for-each': 'error', + 'unicorn/prefer-string-replace-all': 'error', + '@typescript-eslint/prefer-for-of': 'error', + "no-sharp-comments": "off", + "markdown/no-sharp-comments": "off", + // todo: enable + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + }, + }, + // Rules for React files + { + files: '{packages,examples,docs}/**', + extends: [ + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + 'plugin:@next/next/recommended', + ], + rules: { + 'react/prop-types': 'off', + 'react/no-unknown-property': ['error', { ignore: ['jsx'] }], + 'react-hooks/exhaustive-deps': 'error', + 'react/self-closing-comp': 'error', + 'no-restricted-syntax': [ + 'error', + { + // ❌ useMemo(…, []) + selector: + 'CallExpression[callee.name=useMemo][arguments.1.type=ArrayExpression][arguments.1.elements.length=0]', + message: + "`useMemo` with an empty dependency array can't provide a stable reference, use `useRef` instead.", + }, + { + // ❌ z.object(…) + selector: 'MemberExpression[object.name=z] > .property[name=object]', + message: 'Use z.strictObject is more safe.', + }, + ], + 'react/jsx-filename-extension': [ + 'error', + { extensions: ['.tsx', '.jsx'], allow: 'as-needed' }, + ], + 'react/jsx-curly-brace-presence': 'error', + 'react/jsx-boolean-value': 'error', + }, + settings: { + react: { version: 'detect' }, + }, + }, + // Rules for TypeScript files + { + files: '**/*.{ts,tsx,cts,mts}', + extends: [ + // TODO: fix errors + // 'plugin:@typescript-eslint/recommended-requiring-type-checking' + ], + parserOptions: { + project: ['tsconfig.json'], + tsconfigRootDir: './' + }, + rules: { + '@typescript-eslint/no-unnecessary-type-assertion': 'error', + // '@typescript-eslint/consistent-type-imports': 'error', + '@typescript-eslint/non-nullable-type-assertion-style': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + }, + }, + // ⚙️ nextra-theme-docs + { + ...TAILWIND_CONFIG, + files: 'packages/nextra-theme-docs/**', + plugins: ['typescript-sort-keys'], + settings: { + tailwindcss: { + config: 'packages/nextra-theme-docs/tailwind.config.js', + callees: ['cn'], + whitelist: [ + 'nextra-breadcrumb', + 'nextra-bleed', + 'nextra-menu-desktop', + 'nextra-menu-mobile', + ], + }, + }, + rules: { + ...TAILWIND_CONFIG.rules, + 'no-restricted-imports': [ + 'error', + { + name: 'next/link', + message: 'Use local instead', + }, + ], + }, + }, + // ⚙️ nextra-theme-blog + { + ...TAILWIND_CONFIG, + files: 'packages/nextra-theme-blog/**', + settings: { + tailwindcss: { + config: 'packages/nextra-theme-blog/tailwind.config.js', + whitelist: ['subheading-', 'post-item', 'post-item-more'], + }, + }, + }, + // ⚙️ nextra + { + ...TAILWIND_CONFIG, + files: 'packages/nextra/**', + settings: { + tailwindcss: { + config: 'packages/nextra-theme-docs/tailwind.config.js', + callees: ['cn'], + whitelist: ['nextra-code-block', 'nextra-filetree'], + }, + }, + }, + // ⚙️ Docs + { + ...TAILWIND_CONFIG, + files: 'docs/**', + settings: { + tailwindcss: { + config: 'docs/tailwind.config.js', + callees: ['cn'], + whitelist: ['dash-ring', 'theme-1', 'theme-2', 'theme-3', 'theme-4'], + }, + next: { rootDir: 'docs' }, + }, + }, + // ⚙️ SWR-site example + { + ...TAILWIND_CONFIG, + files: 'examples/swr-site/**', + settings: { + tailwindcss: { + config: 'examples/swr-site/tailwind.config.js', + }, + next: { rootDir: 'examples/swr-site' }, + }, + }, + // ⚙️ blog example + { + files: 'examples/blog/**', + settings: { + next: { rootDir: 'examples/blog' }, + }, + }, + // ⚙️ docs example + { + files: 'examples/docs/**', + settings: { + next: { rootDir: 'examples/docs' }, + }, + }, + { + files: [ + 'prettier.config.js', + 'postcss.config.js', + 'tailwind.config.js', + 'next.config.js', + '.eslintrc.cjs', + ], + env: { + node: true, + }, + }, + { + files: 'packages/{nextra,nextra-theme-docs,nextra-theme-blog}/**', + rules: { + // disable rule because we don't have pagesDir in above folders + '@next/next/no-html-link-for-pages': 'off', + }, + }, + { + files: 'packages/nextra/src/**', + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + group: ['fs', 'node:fs'], + message: 'Use `graceful-fs` instead', + }, + ], + }, + ], + }, + }, + { + files: ['**/*.d.ts'], + rules: { + 'no-var': 'off', + }, + }, + ], +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..bd8b79f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,67 @@ +# EXAMPLE +# Source: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +# This is a comment. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# @global-owner1 and @global-owner2 will be requested for +# review when someone opens a pull request. +* @global-owner1 @global-owner2 + +# Order is important; the last matching pattern takes the most +# precedence. When someone opens a pull request that only +# modifies JS files, only @js-owner and not the global +# owner(s) will be requested for a review. +*.js @js-owner #This is an inline comment. + +# You can also use email addresses if you prefer. They'll be +# used to look up users just like we do for commit author +# emails. +*.go docs@example.com + +# Teams can be specified as code owners as well. Teams should +# be identified in the format @org/team-name. Teams must have +# explicit write access to the repository. In this example, +# the octocats team in the octo-org organization owns all .txt files. +*.txt @octo-org/octocats + +# In this example, @doctocat owns any files in the build/logs +# directory at the root of the repository and any of its +# subdirectories. +/build/logs/ @doctocat + +# The `docs/*` pattern will match files like +# `docs/getting-started.md` but not further nested files like +# `docs/build-app/troubleshooting.md`. +docs/* docs@example.com + +# In this example, @octocat owns any file in an apps directory +# anywhere in your repository. +apps/ @octocat + +# In this example, @doctocat owns any file in the `/docs` +# directory in the root of your repository and any of its +# subdirectories. +/docs/ @doctocat + +# In this example, any change inside the `/scripts` directory +# will require approval from @doctocat or @octocat. +/scripts/ @doctocat @octocat + +# In this example, @octocat owns any file in a `/logs` directory such as +# `/build/logs`, `/scripts/logs`, and `/deeply/nested/logs`. Any changes +# in a `/logs` directory will require approval from @octocat. +**/logs @octocat + +# In this example, @octocat owns any file in the `/apps` +# directory in the root of your repository except for the `/apps/github` +# subdirectory, as its owners are left empty. +/apps/ @octocat +/apps/github + +# In this example, @octocat owns any file in the `/apps` +# directory in the root of your repository except for the `/apps/github` +# subdirectory, as this subdirectory has its own owner @doctocat +/apps/ @octocat +/apps/github @doctocat \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d252f8b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,29 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: npm + directory: '/' # Location of package manifests + rebase-strategy: 'disabled' # use dependabot-rebase-stale + schedule: + interval: 'daily' + commit-message: + prefix: chore + prefix-development: chore + include: scope + ignore: + - dependency-name: '@types/node' + groups: + patches: + update-types: + - 'patch' + low-risk: + patterns: + - '@calcom/embed-react' + - '@splinetool/react-spline' + - 'lucide-react' + - 'posthog-js' + - 'react-icons' diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml new file mode 100644 index 0000000..9eb5e8b --- /dev/null +++ b/.github/workflows/nextjs_bundle_analysis.yml @@ -0,0 +1,130 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +name: 'Next.js Bundle Analysis' + +on: + pull_request: + push: + branches: + - main # change this if your default branch is named differently + workflow_dispatch: + +defaults: + run: + # change this if your nextjs app does not live at the root of the repo + working-directory: ./ + +permissions: + contents: read # for checkout repository + actions: read # for fetching base branch bundle stats + pull-requests: write # for comments + +jobs: + analyze: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: 18 + + # - name: Install dependencies + # uses: bahmutov/npm-install@v1 + + # If pnpm is used, you need to switch the previous step with the following one. pnpm does not create a package-lock.json + # so the step above will fail to pull dependencies + - uses: pnpm/action-setup@v2 + name: Install pnpm + id: pnpm-install + with: + version: 8 + run_install: true + + # DO NOT CACHE DUE TO NEXTRA CACHING ISSUES + # - name: Restore next build + # uses: actions/cache@v3 + # id: restore-build-cache + # env: + # cache-name: cache-next-build + # with: + # # if you use a custom build directory, replace all instances of `.next` in this file with your build directory + # # ex: if your app builds to `dist`, replace `.next` with `dist` + # path: .next/cache + # # change this if you prefer a more strict cache + # key: ${{ runner.os }}-build-${{ env.cache-name }} + + - name: Build next.js app + # change this if your site requires a custom build command + run: ./node_modules/.bin/next build + + # Here's the first place where next-bundle-analysis' own script is used + # This step pulls the raw bundle stats for the current bundle + - name: Analyze bundle + run: npx -p nextjs-bundle-analysis report + + - name: Upload bundle + uses: actions/upload-artifact@v3 + with: + name: bundle + path: .next/analyze/__bundle_analysis.json + + - name: Download base branch bundle stats + uses: dawidd6/action-download-artifact@v2 + if: success() && github.event.number + with: + workflow: nextjs_bundle_analysis.yml + branch: ${{ github.event.pull_request.base.ref }} + path: .next/analyze/base + + # And here's the second place - this runs after we have both the current and + # base branch bundle stats, and will compare them to determine what changed. + # There are two configurable arguments that come from package.json: + # + # - budget: optional, set a budget (bytes) against which size changes are measured + # it's set to 350kb here by default, as informed by the following piece: + # https://infrequently.org/2021/03/the-performance-inequality-gap/ + # + # - red-status-percentage: sets the percent size increase where you get a red + # status indicator, defaults to 20% + # + # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis` + # entry in your package.json file. + - name: Compare with base branch bundle + if: success() && github.event.number + run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare + + - name: Get Comment Body + id: get-comment-body + if: success() && github.event.number + # https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings + run: | + echo "body<> $GITHUB_OUTPUT + echo "$(cat .next/analyze/__bundle_analysis_comment.txt)" >> $GITHUB_OUTPUT + echo EOF >> $GITHUB_OUTPUT + + - name: Find Comment + uses: peter-evans/find-comment@v2 + if: success() && github.event.number + id: fc + with: + issue-number: ${{ github.event.number }} + body-includes: '' + + - name: Create Comment + uses: peter-evans/create-or-update-comment@v2 + if: success() && github.event.number && steps.fc.outputs.comment-id == 0 + with: + issue-number: ${{ github.event.number }} + body: ${{ steps.get-comment-body.outputs.body }} + + - name: Update Comment + uses: peter-evans/create-or-update-comment@v2 + if: success() && github.event.number && steps.fc.outputs.comment-id != 0 + with: + issue-number: ${{ github.event.number }} + body: ${{ steps.get-comment-body.outputs.body }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7265064 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +.next +node_modules +.vercel + +.env.local +.env +.env*.local + +# next sitemap +public/robots.txt +public/sitemap*.xml + +# we use pnpm +package-lock.json +yarn.lock + + +# Mac +.DS_Store + +# eslint +.eslintcache \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..cb2c84d --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +pnpm lint-staged diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..6c59086 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +enable-pre-post-scripts=true diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..2fb4f8e --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v18.18 \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..0dbc1fb --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + trailingComma: 'all', + tabWidth: 2, + semi: false, + singleQuote: true, + printWidth: 100, +} diff --git a/LICENSE b/LICENSE index 2ad6eda..49a2249 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 noreplylibrechatai +Copyright (c) 2024 LibreChat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000..652ee0a --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# LibreChat Docs + +Based on [Nextra](https://nextra.site/) + +## Local Development + +Pre-requisites: Node.js 18+, pnpm 9+ + +1. Optional: Create env based on [.env.template](./.env.template) +2. Run `pnpm i` to install the dependencies. +3. Run `pnpm dev` to start the development server on localhost:3333 +4. Run `pnpm build` to build... +5. Run `pnpm start` to start the production server on localhost:3333 + +⚠️ **Note: try building prod before making a PR** + +## Bundle analysis + +Run `pnpm run analyze` to analyze the bundle size of the production build using `@next/bundle-analyzer`. diff --git a/components.json b/components.json new file mode 100644 index 0000000..008ff52 --- /dev/null +++ b/components.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "style.css", + "baseColor": "slate", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/components/Author/AuthorPage.tsx b/components/Author/AuthorPage.tsx new file mode 100644 index 0000000..eb8956c --- /dev/null +++ b/components/Author/AuthorPage.tsx @@ -0,0 +1,88 @@ +import React, { useEffect, useState } from 'react' +import { getPagesUnderRoute } from 'nextra/context' +import { type Page } from 'nextra' +import { SocialIcon } from 'react-social-icons' +import Image from 'next/image' +import Link from 'next/link' + +interface AuthorMetadata { + authorid: string + subtitle: string + name: string + bio: string + ogImage: string + socials?: Record +} + +const AuthorCard: React.FC<{ author: AuthorMetadata }> = ({ author }) => { + const [isClient, setIsClient] = useState(false) + + useEffect(() => { + setIsClient(true) + }, []) + + const socialsEntries = Object.entries(author.socials ?? {}).filter(([, value]) => !!value) + + return ( + +
+
+ {author.name} +
+

{author.name}

+

{author.subtitle}

+
+ {isClient && + socialsEntries.map(([key, value]) => ( + e.stopPropagation()} + > + + + ))} +
+
+ + ) +} + +const AuthorPage: React.FC = () => { + const allAuthors = getPagesUnderRoute('/authors') as Array + + const authors = allAuthors.filter((author) => !!author.frontMatter.authorid) + + return ( +
+

+ Our Authors +

+
+ {authors.map((author) => ( + + ))} +
+
+ ) +} + +export default AuthorPage diff --git a/components/Author/AuthorProfile.tsx b/components/Author/AuthorProfile.tsx new file mode 100644 index 0000000..9a3d429 --- /dev/null +++ b/components/Author/AuthorProfile.tsx @@ -0,0 +1,129 @@ +import React, { useEffect, useState } from 'react' +import { getPagesUnderRoute } from 'nextra/context' +import { type Page } from 'nextra' +import { SocialIcon } from 'react-social-icons' +import BlogCard from '../blog/BlogCard' +import Image from 'next/image' +import { Cards } from 'nextra/components' +import { Blog } from '@/components/CardIcons/Blog' +import { OurAuthors } from '@/components/CardIcons/OurAuthors' + +//TODO: Fix Mobile view to better handle more than 4 socials; +//TODO: Better fallback social icon (the default one is the "share" icon) +//TODO: Tag selection on "Recent Posts by" (author pages) +//TODO: fix profile pic position when no bio + +interface AuthorMetadata { + authorid: string + subtitle: string + name: string + bio: string + ogImage: string + socials?: Record // Dynamically match social media platforms +} + +interface AuthorProfileProps { + authorId: string +} + +const AuthorProfile: React.FC = ({ authorId }) => { + const authors = getPagesUnderRoute('/authors') as Array + const author = authors.find((a) => a.frontMatter.authorid === authorId)?.frontMatter + const blogPosts = getPagesUnderRoute('/blog') as Array + + // Filter posts by the current authorId + const authorPosts = blogPosts.filter((post) => post.frontMatter.authorid === authorId) + const sortedAuthorPosts = authorPosts.sort( + (a, b) => new Date(b.frontMatter.date).getTime() - new Date(a.frontMatter.date).getTime(), + ) + + if (!author) { + return
Author not found!
+ } + + const socialsEntries = Object.entries(author.socials ?? {}).filter(([, value]) => !!value) + + // State to track whether the component is rendered on the client side + const [isClient, setIsClient] = useState(false) + + useEffect(() => { + setIsClient(true) + }, []) + + return ( + <> +
+
+

{author.name}

+

+ {author.subtitle} +

+ {author.bio &&

{author.bio}

} +
+ +
+ {author.name} + +
+ {isClient && + socialsEntries.map(([key, value]) => ( + + + + ))} +
+
+
+
+

Recent Posts by {author.name}

+
+ {sortedAuthorPosts.map((post) => ( + console.log('Tag clicked:', tag)} + selectedTags={undefined} + /> + ))} +
+
+
+ + } image> + {null} + + } image> + {null} + + +
+
+ + ) +} + +export default AuthorProfile diff --git a/components/Author/Authors.tsx b/components/Author/Authors.tsx new file mode 100644 index 0000000..24d2449 --- /dev/null +++ b/components/Author/Authors.tsx @@ -0,0 +1,47 @@ +import Image from 'next/image' +import { getPagesUnderRoute } from 'nextra/context' +import { Page } from 'nextra' + +type AuthorPage = Page & { + frontMatter: { + name: string + ogImage: string + authorid: string + } +} + +export const Author = ({ authorid }: { authorid: string }) => { + const authorPages = getPagesUnderRoute('/authors') + const page = authorPages?.find( + (page) => (page as AuthorPage).frontMatter.authorid === authorid, + ) as AuthorPage + + if (!page) { + // Handle the case when the author page is not found + console.error('Author page not found for authorid:', authorid) + return null + } + + const { name, ogImage } = page.frontMatter + + return ( + + ) +} diff --git a/components/Author/AuthorsSmall.tsx b/components/Author/AuthorsSmall.tsx new file mode 100644 index 0000000..2322814 --- /dev/null +++ b/components/Author/AuthorsSmall.tsx @@ -0,0 +1,41 @@ +import Image from 'next/image' +import { getPagesUnderRoute } from 'nextra/context' +import { Page } from 'nextra' + +type AuthorPage = Page & { + frontMatter: { + name: string + ogImage: string + authorid: string + } +} + +export const AuthorSmall = ({ authorid }: { authorid: string }) => { + const authorPages = getPagesUnderRoute('/authors') + const page = authorPages?.find( + (page) => (page as AuthorPage).frontMatter.authorid === authorid, + ) as AuthorPage + + if (!page) { + // Handle the case when the author page is not found + console.error('Author page not found for authorid:', authorid) + return null + } + + const { name, ogImage } = page.frontMatter + + return ( +
+
+ {`Picture + {name} +
+
+ ) +} diff --git a/components/CardIcons/AboutLogo.tsx b/components/CardIcons/AboutLogo.tsx new file mode 100644 index 0000000..33dccfa --- /dev/null +++ b/components/CardIcons/AboutLogo.tsx @@ -0,0 +1,36 @@ +import Image from 'next/image' + +export function Logo() { + return ( + <> +
+ {/* Image */} + LibreChat Logo + {/* Text */} + + About LibreChat... + + {/* CSS for hover effect */} + +
+ + ) +} diff --git a/components/CardIcons/Blog.tsx b/components/CardIcons/Blog.tsx new file mode 100644 index 0000000..edbc4fa --- /dev/null +++ b/components/CardIcons/Blog.tsx @@ -0,0 +1,34 @@ +import Image from 'next/image' + +export function Blog() { + return ( + <> +
+ {/* Image */} + Blog Logo + {/* Text */} + Blog + {/* CSS for hover effect */} + +
+ + ) +} diff --git a/components/CardIcons/Changelog.tsx b/components/CardIcons/Changelog.tsx new file mode 100644 index 0000000..d905fcc --- /dev/null +++ b/components/CardIcons/Changelog.tsx @@ -0,0 +1,34 @@ +import Image from 'next/image' + +export function Changelog() { + return ( + <> +
+ {/* Image */} + Changelog Logo + {/* Text */} + Changelog + {/* CSS for hover effect */} + +
+ + ) +} diff --git a/components/CardIcons/OurAuthors.tsx b/components/CardIcons/OurAuthors.tsx new file mode 100644 index 0000000..b169fac --- /dev/null +++ b/components/CardIcons/OurAuthors.tsx @@ -0,0 +1,34 @@ +import Image from 'next/image' + +export function OurAuthors() { + return ( + <> +
+ {/* Image */} + OurAuthors Logo + {/* Text */} + Our Authors + {/* CSS for hover effect */} + +
+ + ) +} diff --git a/components/CardIcons/Roadmap.tsx b/components/CardIcons/Roadmap.tsx new file mode 100644 index 0000000..0c73856 --- /dev/null +++ b/components/CardIcons/Roadmap.tsx @@ -0,0 +1,36 @@ +import Image from 'next/image' + +export function Roadmap() { + return ( + <> +
+ {/* Image */} + Roadmap Logo + {/* Text */} + + 2024 Roadmap + + {/* CSS for hover effect */} + +
+ + ) +} diff --git a/components/CardIcons/ToolKit.tsx b/components/CardIcons/ToolKit.tsx new file mode 100644 index 0000000..a65aed3 --- /dev/null +++ b/components/CardIcons/ToolKit.tsx @@ -0,0 +1,34 @@ +import Image from 'next/image' + +export function ToolKit() { + return ( + <> +
+ {/* Image */} + ToolKit Logo + {/* Text */} + ToolKit + {/* CSS for hover effect */} + +
+ + ) +} diff --git a/components/FooterMenu.tsx b/components/FooterMenu.tsx new file mode 100644 index 0000000..5bcbb4b --- /dev/null +++ b/components/FooterMenu.tsx @@ -0,0 +1,165 @@ +import Link from 'next/link' +import { SocialIcon } from 'react-social-icons' + +const menuItems: { + heading: string + items: { name: string; href: string }[] +}[] = [ + { + heading: 'About', + items: [ + { + name: 'About', + href: '/about', + }, + { name: 'Contact Us', href: '/about#contact-us' }, + ], + }, + { + heading: 'Resources', + items: [ + { + name: 'Changelog', + href: '/changelog', + }, + { + name: 'Roadmap', + href: '/blog/2024-02-19_2024_roadmap', + }, + { + name: 'Demo', + href: 'https://demo.librechat.cfd/', + }, + { + name: 'Status', + href: 'https://status.librechat.ai/', + }, + ], + }, + { + heading: 'Documentation', + items: [ + { + name: 'Get Started', + href: '/docs', + }, + { + name: 'Local Install', + href: '/docs/local', + }, + { + name: 'Remote Install', + href: '/docs/remote', + }, + ], + }, + { + heading: 'Blog', + items: [ + { name: 'Blog', href: '/blog' }, + { name: 'Blog Authors', href: '/authors' }, + ], + }, + { + heading: 'Newsletter', + items: [ + { + name: 'Subscribe', + href: '/subscribe', + }, + { + name: 'Unsubscribe', + href: '/unsubscribe', + }, + ], + }, + { + heading: 'Legal', + items: [ + { + name: 'Terms of services', + href: '/tos', + }, + { + name: 'Privacy policy', + href: '/privacy', + }, + { + name: 'Cookie policy', + href: '/cookie', + }, + ], + }, +] + +const FooterMenu = () => { + return ( +
+
+ {menuItems.map((menu) => ( +
+

{menu.heading}

+
    + {menu.items.map((item) => ( +
  • + + {item.name} + +
  • + ))} +
+
+ ))} +
+
© {new Date().getFullYear()} LibreChat
+
+ + + + + + +
+
+
+
+ ) +} + +export default FooterMenu diff --git a/components/Frame.tsx b/components/Frame.tsx new file mode 100644 index 0000000..2e2f63b --- /dev/null +++ b/components/Frame.tsx @@ -0,0 +1,35 @@ +import { cn } from '@/lib/utils' + +export const Frame = ({ + children, + className, + border = false, + fullWidth = false, + transparent = false, +}: { + children: React.ReactNode + className?: string + border?: boolean + fullWidth?: boolean + transparent?: boolean +}) => ( +
+
*]:mt-0', + fullWidth && 'max-w-full', + transparent && 'bg-transparent', + border && '[&>*]:-mb-1', + )} + > + {children} +
+
+) diff --git a/components/Header.tsx b/components/Header.tsx new file mode 100644 index 0000000..f394873 --- /dev/null +++ b/components/Header.tsx @@ -0,0 +1,42 @@ +import { Button } from '@/components/ui/button' +import { cn } from '@/lib/utils' +import { ArrowRight } from 'lucide-react' +import Link from 'next/link' +import React from 'react' + +export const Header = ({ + title, + description, + className, + button, + h = 'h2', +}: { + title?: React.ReactNode + description?: React.ReactNode + button?: { href: string; text: string } + h?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' + className?: string +}) => { + const TitleTag: React.ElementType = h + return ( +
+ {title && ( + + {title} + + )} + {description && ( +

+ {description} +

+ )} + {button && ( + + )} +
+ ) +} diff --git a/components/LogoContextMenu.tsx b/components/LogoContextMenu.tsx new file mode 100644 index 0000000..94b7f41 --- /dev/null +++ b/components/LogoContextMenu.tsx @@ -0,0 +1,70 @@ +import { + DropdownMenuContent, + DropdownMenuTrigger, + DropdownMenu, + DropdownMenuItem, + DropdownMenuSeparator, +} from './ui/dropdown-menu' +import { Download, ExternalLink } from 'lucide-react' + +const LogoContextMenu: React.FC<{ + open: boolean + setOpen: (open: boolean) => void +}> = ({ open, setOpen }) => { + return ( + + + + { + e.preventDefault() + window.open('/', '_blank') + }} + > + + Open in new tab + + + { + e.preventDefault() + window.open('/librechat.png', '_blank') + }} + > + + Logo (png) + + { + e.preventDefault() + window.open('/librechat.svg', '_blank') + }} + > + + Logo (svg) + + + { + e.preventDefault() + window.open('/librechat_alt.png', '_blank') + }} + > + + Docs Logo (png) + + { + e.preventDefault() + window.open('/librechat_alt.svg', '_blank') + }} + > + + Docs Logo (svg) + + + + ) +} + +export default LogoContextMenu diff --git a/components/Newsletter/SubscribeForm.tsx b/components/Newsletter/SubscribeForm.tsx new file mode 100644 index 0000000..1409702 --- /dev/null +++ b/components/Newsletter/SubscribeForm.tsx @@ -0,0 +1,66 @@ +import React, { useState } from 'react' +import toast, { Toaster } from 'react-hot-toast' +import validator from 'validator' +import style from './newsletterform.module.css' + +const SubscribeForm = () => { + const [email, setEmail] = useState('') + const [isLoading, setIsLoading] = useState(false) + + const handleSubmit = async (e) => { + e.preventDefault() + + if (!validator.isEmail(email)) { + toast.error('Valid email is required') + return + } + + setIsLoading(true) + + try { + const response = await fetch('/api/subscribe', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email }), + }) + + if (response.status === 201) { + toast.success('Subscription successful') + setEmail('') + } else if (response.status === 409) { + toast.error('Email already subscribed') + } else { + toast.error('Subscription failed') + } + } catch (error) { + toast.error('Subscription failed') + } finally { + setIsLoading(false) + } + } + + return ( +
+ +
+

Subscribe to Our Newsletter

+
+ setEmail(e.target.value)} + className={style[`email-input`]} + /> + +
+
+
+ ) +} + +export default SubscribeForm diff --git a/components/Newsletter/UnsubscribeForm.tsx b/components/Newsletter/UnsubscribeForm.tsx new file mode 100644 index 0000000..d8539f7 --- /dev/null +++ b/components/Newsletter/UnsubscribeForm.tsx @@ -0,0 +1,66 @@ +import { useState } from 'react' +import toast, { Toaster } from 'react-hot-toast' +import validator from 'validator' +import style from './newsletterform.module.css' + +const UnsubscribeForm = () => { + const [email, setEmail] = useState('') + const [isLoading, setIsLoading] = useState(false) + + const handleSubmit = async (e) => { + e.preventDefault() + + if (!validator.isEmail(email)) { + toast.error('Invalid email format') + return + } + + setIsLoading(true) + + try { + const response = await fetch('/api/unsubscribe', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email }), + }) + + if (response.status === 200) { + toast.success('Unsubscription successful') + setEmail('') + } else if (response.status === 404) { + toast.error('Subscriber not found') + } else { + toast.error('Unsubscription failed') + } + } catch { + toast.error('Unsubscription failed') + } finally { + setIsLoading(false) + } + } + + return ( +
+ +
+

Unsubscribe From Our Newsletter

+
+ setEmail(e.target.value)} + className={style[`email-input`]} + /> + +
+
+
+ ) +} + +export default UnsubscribeForm diff --git a/components/Newsletter/newsletterform.module.css b/components/Newsletter/newsletterform.module.css new file mode 100644 index 0000000..9548f0e --- /dev/null +++ b/components/Newsletter/newsletterform.module.css @@ -0,0 +1,74 @@ +.container { + text-align: center; +} + +.form-wrapper { + max-width: 400px; + margin: 0 auto; + border-radius: 10px; + overflow: hidden; + background-color: #f1f1f1; +} +:global(.dark) .form-wrapper { + background-color: #171717; +} +.form-title { + padding: 15px; + color:#454545; +} + +:global(.dark) .form-title { + color:#9b9b9b; +} + +.form-container { + padding: 20px; +} + +.email-input { + padding: 8px; + /* border: 1px solid #3e3e3e; */ + border-radius: 5px; + margin-bottom: 10px; + width: 100%; + background-color: #fff; +} + +.email-input::placeholder { + color: #5a5a5a; +} +.email-input::placeholder { + color: #5a5a5a; +} + +:global(.dark) .email-input { + background-color: #29292a; +} + +.subscribe-button { + padding: 8px 16px; + background: linear-gradient(-45deg, #ffa63d, #ff3d77, #338aff, #3cf0c5); + background-size: 600%; + animation: anime 16s linear infinite; + color: rgba(255, 255, 255, 0.9); + border: none; + border-radius: 5px; + cursor: pointer; + width: 100%; +} + +.subscribe-button:hover { + filter: brightness(110%); +} + +@keyframes anime { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} \ No newline at end of file diff --git a/components/Tweet.tsx b/components/Tweet.tsx new file mode 100644 index 0000000..a200ab4 --- /dev/null +++ b/components/Tweet.tsx @@ -0,0 +1,8 @@ +import { cn } from '@/lib/utils' +import { Tweet as ReactTweet } from 'react-tweet' + +export const Tweet = ({ id, className }: { id: string; className?: string }) => ( +
+ +
+) diff --git a/components/Video.tsx b/components/Video.tsx new file mode 100644 index 0000000..e607993 --- /dev/null +++ b/components/Video.tsx @@ -0,0 +1,77 @@ +import { cn } from '@/lib/utils' +import { MediaPlayer, MediaOutlet, useMediaRemote, useMediaStore } from '@vidstack/react' +import { Play } from 'lucide-react' +import { useState, useRef } from 'react' + +export const Video = ({ + src, + poster, + aspectRatio, + className, + gifStyle = false, + title, +}: { + src: string + poster?: string + aspectRatio?: number + gifStyle?: boolean + className?: string + title?: string +}) => { + const [panelDismissed, setPanelDismissed] = useState(false) + const mediaPlayerRef = useRef(null) + const remote = useMediaRemote(mediaPlayerRef) + const { duration } = useMediaStore(mediaPlayerRef) + const durationString = duration + ? `${Math.floor(duration / 60)}:${Math.floor(duration % 60)} min` + : null + + return ( + + {gifStyle ? ( + // Capture mouse events, they broke scrolling on iOS +
+ ) : panelDismissed ? null : ( + // Overlay with play button and poster image +
{ + remote.startLoading() + }} + onClick={() => { + remote.play() + setPanelDismissed(true) + }} + > +
+ +
+
+ + {title && {title}} + {durationString && {durationString}} + +
+
+ )} + + + ) +} diff --git a/components/analytics/hubspot.tsx b/components/analytics/hubspot.tsx new file mode 100644 index 0000000..b007688 --- /dev/null +++ b/components/analytics/hubspot.tsx @@ -0,0 +1,11 @@ +import Script from 'next/script' + +export const Hubspot = () => { + return