[
  {
    "path": ".gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n.pnp\n.pnp.js\n\n# testing\ncoverage\n\n# next.js\n.next/\n.swc/\nout/\nbuild\n\n# expo\n.expo\n\n# misc\n.DS_Store\n*.pem\ndist\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n.env\n\n# turbo\n.turbo\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"arrowParens\": \"always\"\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2024 Convex, Inc.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Fullstack Monorepo Template\n\nThis repo is a modern TypeScript monorepo for a shared notes app across web and native.\n\nIt currently uses:\n\n- [Turborepo](https://turbo.build/repo)\n- [pnpm](https://pnpm.io/)\n- [Next.js 16](https://nextjs.org/) with the App Router\n- [Expo SDK 55](https://docs.expo.dev/) with Expo Router\n- [React 19](https://react.dev/)\n- [Convex](https://convex.dev/)\n- [Clerk](https://clerk.com/)\n- [OpenAI](https://platform.openai.com/docs/quickstart?api-mode=responses) for optional note summaries\n\n## What’s inside\n\n- `apps/web` - the Next.js web app\n- `apps/native` - the Expo native app\n- `packages/backend` - the Convex backend and generated API types\n\n## Quick start\n\n### 1. Install dependencies\n\n```sh\npnpm install\n```\n\n### 2. Configure Convex\n\nRun the backend setup command:\n\n```sh\npnpm --filter @packages/backend setup\n```\n\nThis will log you into Convex, create or connect a project, and generate `packages/backend/.env.local`.\n\n### 3. Configure Clerk for Convex\n\nFollow the official [Convex + Clerk guide](https://docs.convex.dev/auth/clerk).\n\nIn the Clerk dashboard, enable the Convex integration and copy the Clerk JWT issuer domain. Add it to your Convex environment variables as:\n\n```sh\nCLERK_JWT_ISSUER_DOMAIN=https://your-frontend-api.clerk.accounts.dev\n```\n\nIf you want native social login, enable Google and Apple in Clerk as well.\n\nIf you want AI summaries, also add:\n\n```sh\nOPENAI_API_KEY=...\n```\n\nto your Convex environment variables.\n\n### 4. Configure the app env files\n\nCreate `.env.local` files in `apps/web` and `apps/native` from the provided `.example.env` files.\n\n- Use `CONVEX_URL` from `packages/backend/.env.local` for both `NEXT_PUBLIC_CONVEX_URL` and `EXPO_PUBLIC_CONVEX_URL`\n- Use your Clerk publishable key for both app env files\n- Use your Clerk secret key in `apps/web/.env.local`\n\n### 5. Run the apps\n\n```sh\npnpm dev\n```\n\nThis runs the backend, web app, and native app through Turbo.\n\n## Deploying\n\nFrom `apps/web`, use Convex to deploy the backend and build the web app:\n\n```sh\ncd ../../packages/backend && pnpm exec convex deploy --cmd 'cd ../../apps/web && pnpm build' --cmd-url-env-var-name NEXT_PUBLIC_CONVEX_URL\n```\n\n`apps/web/vercel.json` is already set up for this flow on Vercel.\n\n## Adding dependencies\n\nInstall dependencies in the package that actually uses them.\n\nExamples:\n\n```sh\npnpm --filter web-app add mypackage@latest\npnpm --filter native-app add mypackage@latest\npnpm --filter @packages/backend add mypackage@latest\n```\n\n## Notes\n\n- The native app uses Expo Router route groups under `apps/native/src/app`\n- The web app protects note routes with `apps/web/src/proxy.ts`\n- Convex enforces note ownership server-side in `packages/backend/convex/notes.ts`\n"
  },
  {
    "path": "apps/native/.example.env",
    "content": "EXPO_PUBLIC_CONVEX_URL=\nEXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=\n"
  },
  {
    "path": "apps/native/.gitignore",
    "content": "node_modules/\n.expo/\ndist/\nnpm-debug.*\n*.jks\n*.p8\n*.p12\n*.key\n*.mobileprovision\n*.orig.*\nweb-build/\n\n# macOS\n.DS_Store\n\n# Temporary files created by Metro to check the health of the file watcher\n.metro-health-check*\n\n# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb\n# The following patterns were generated by expo-cli\n\nexpo-env.d.ts\n# @end expo-cli"
  },
  {
    "path": "apps/native/ConvexClientProvider.tsx",
    "content": "import { type ReactNode } from \"react\";\nimport { ClerkProvider, useAuth } from \"@clerk/clerk-expo\";\nimport { tokenCache } from \"@clerk/clerk-expo/token-cache\";\nimport { ConvexReactClient } from \"convex/react\";\nimport { ConvexProviderWithClerk } from \"convex/react-clerk\";\n\nconst convexUrl = process.env.EXPO_PUBLIC_CONVEX_URL;\nconst clerkPublishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;\n\nif (!convexUrl)\n  throw new Error(\n    \"Missing EXPO_PUBLIC_CONVEX_URL for the native Convex client\",\n  );\n\nif (!clerkPublishableKey)\n  throw new Error(\n    \"Missing EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY for the native Clerk client\",\n  );\n\nconst convex = new ConvexReactClient(convexUrl);\n\nexport default function ConvexClientProvider({\n  children,\n}: {\n  children: ReactNode;\n}) {\n  return (\n    <ClerkProvider publishableKey={clerkPublishableKey} tokenCache={tokenCache}>\n      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>\n        {children}\n      </ConvexProviderWithClerk>\n    </ClerkProvider>\n  );\n}\n"
  },
  {
    "path": "apps/native/app.json",
    "content": "{\n  \"expo\": {\n    \"newArchEnabled\": true,\n    \"name\": \"NotesContract\",\n    \"slug\": \"NotesContract\",\n    \"scheme\": \"notescontract\",\n    \"version\": \"1.0.0\",\n    \"orientation\": \"portrait\",\n    \"icon\": \"./assets/icon.png\",\n    \"userInterfaceStyle\": \"light\",\n    \"splash\": {\n      \"image\": \"./assets/splash.png\",\n      \"resizeMode\": \"contain\",\n      \"backgroundColor\": \"#0D87E1\"\n    },\n    \"assetBundlePatterns\": [\"**/*\"],\n    \"ios\": {\n      \"supportsTablet\": true\n    },\n    \"android\": {\n      \"adaptiveIcon\": {\n        \"foregroundImage\": \"./assets/adaptive-icon.png\",\n        \"backgroundColor\": \"#ffffff\"\n      }\n    },\n    \"web\": {\n      \"bundler\": \"metro\",\n      \"favicon\": \"./assets/favicon.png\"\n    },\n    \"plugins\": [\n      [\n        \"expo-router\",\n        {\n          \"root\": \"./src/app\"\n        }\n      ],\n      \"expo-font\",\n      \"expo-secure-store\"\n    ],\n    \"experiments\": {\n      \"typedRoutes\": true\n    }\n  }\n}\n"
  },
  {
    "path": "apps/native/babel.config.js",
    "content": "module.exports = function (api) {\n  api.cache(true);\n  return {\n    presets: [\"babel-preset-expo\"],\n  };\n};\n"
  },
  {
    "path": "apps/native/index.tsx",
    "content": "import * as WebBrowser from \"expo-web-browser\";\n\nWebBrowser.maybeCompleteAuthSession();\n\nimport \"expo-router/entry\";\n"
  },
  {
    "path": "apps/native/metro.config.js",
    "content": "const { getDefaultConfig } = require(\"expo/metro-config\");\n\nmodule.exports = getDefaultConfig(__dirname);\n"
  },
  {
    "path": "apps/native/package.json",
    "content": "{\n  \"name\": \"native-app\",\n  \"version\": \"1.0.0\",\n  \"main\": \"index.tsx\",\n  \"scripts\": {\n    \"dev\": \"expo start\",\n    \"start\": \"expo start\",\n    \"android\": \"expo start --android\",\n    \"ios\": \"expo start --ios\",\n    \"web\": \"expo start --web\",\n    \"typecheck\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@clerk/clerk-expo\": \"^2.19.31\",\n    \"@expo/vector-icons\": \"^15.1.1\",\n    \"@packages/backend\": \"workspace:*\",\n    \"expo\": \"~55.0.16\",\n    \"expo-asset\": \"~55.0.16\",\n    \"expo-auth-session\": \"~55.0.15\",\n    \"expo-constants\": \"~55.0.15\",\n    \"expo-font\": \"~55.0.6\",\n    \"expo-linking\": \"~55.0.14\",\n    \"expo-router\": \"~55.0.13\",\n    \"expo-secure-store\": \"~55.0.13\",\n    \"expo-system-ui\": \"~55.0.16\",\n    \"expo-web-browser\": \"~55.0.14\",\n    \"react\": \"19.2.0\",\n    \"react-dom\": \"19.2.0\",\n    \"react-native\": \"0.83.6\",\n    \"react-native-gesture-handler\": \"~2.30.1\",\n    \"react-native-keyboard-aware-scroll-view\": \"^0.9.5\",\n    \"react-native-reanimated\": \"~4.2.1\",\n    \"react-native-responsive-fontsize\": \"^0.5.1\",\n    \"react-native-safe-area-context\": \"5.6.2\",\n    \"react-native-screens\": \"~4.23.0\",\n    \"react-native-web\": \"~0.21.2\",\n    \"react-native-worklets\": \"0.7.4\"\n  },\n  \"devDependencies\": {\n    \"@babel/core\": \"7.29.0\",\n    \"@types/jest\": \"29.5.14\",\n    \"@types/react\": \"19.2.14\",\n    \"@types/react-test-renderer\": \"19.1.0\",\n    \"jest\": \"29.7.0\",\n    \"jest-expo\": \"55.0.16\",\n    \"react-test-renderer\": \"19.2.0\",\n    \"typescript\": \"5.9.3\"\n  },\n  \"private\": true\n}\n"
  },
  {
    "path": "apps/native/src/app/(app)/_layout.tsx",
    "content": "import { useAuth } from \"@clerk/clerk-expo\";\nimport { Redirect, Stack } from \"expo-router\";\n\nexport default function AppLayout() {\n  const { isLoaded, isSignedIn } = useAuth();\n\n  if (!isLoaded) return null;\n\n  if (!isSignedIn) return <Redirect href=\"/sign-in\" />;\n\n  return <Stack screenOptions={{ headerShown: false }} />;\n}\n"
  },
  {
    "path": "apps/native/src/app/(app)/index.tsx",
    "content": "export { default } from \"../../screens/NotesDashboardScreen\";\n"
  },
  {
    "path": "apps/native/src/app/(app)/notes/[noteId].tsx",
    "content": "export { default } from \"../../../screens/InsideNoteScreen\";\n"
  },
  {
    "path": "apps/native/src/app/(app)/notes/new.tsx",
    "content": "export { default } from \"../../../screens/CreateNoteScreen\";\n"
  },
  {
    "path": "apps/native/src/app/(auth)/_layout.tsx",
    "content": "import { useAuth } from \"@clerk/clerk-expo\";\nimport { Redirect, Stack } from \"expo-router\";\n\nexport default function AuthLayout() {\n  const { isLoaded, isSignedIn } = useAuth();\n\n  if (!isLoaded) return null;\n\n  if (isSignedIn) return <Redirect href=\"/\" />;\n\n  return <Stack screenOptions={{ headerShown: false }} />;\n}\n"
  },
  {
    "path": "apps/native/src/app/(auth)/sign-in.tsx",
    "content": "export { default } from \"../../screens/LoginScreen\";\n"
  },
  {
    "path": "apps/native/src/app/_layout.tsx",
    "content": "import { useFonts } from \"expo-font\";\nimport { Stack } from \"expo-router\";\nimport { Platform, StatusBar, View } from \"react-native\";\nimport ConvexClientProvider from \"../../ConvexClientProvider\";\n\nconst statusBarHeight =\n  Platform.OS === \"ios\" ? 50 : (StatusBar.currentHeight ?? 0);\n\nexport default function RootLayout() {\n  const [loaded] = useFonts({\n    Bold: require(\"../assets/fonts/Inter-Bold.ttf\"),\n    SemiBold: require(\"../assets/fonts/Inter-SemiBold.ttf\"),\n    Medium: require(\"../assets/fonts/Inter-Medium.ttf\"),\n    Regular: require(\"../assets/fonts/Inter-Regular.ttf\"),\n    MBold: require(\"../assets/fonts/Montserrat-Bold.ttf\"),\n    MSemiBold: require(\"../assets/fonts/Montserrat-SemiBold.ttf\"),\n    MMedium: require(\"../assets/fonts/Montserrat-Medium.ttf\"),\n    MRegular: require(\"../assets/fonts/Montserrat-Regular.ttf\"),\n    MLight: require(\"../assets/fonts/Montserrat-Light.ttf\"),\n  });\n\n  if (!loaded) return null;\n\n  return (\n    <ConvexClientProvider>\n      <View style={{ flex: 1 }}>\n        <View style={{ height: statusBarHeight, backgroundColor: \"#0D87E1\" }}>\n          <StatusBar\n            translucent\n            backgroundColor=\"#0D87E1\"\n            barStyle=\"light-content\"\n          />\n        </View>\n        <Stack screenOptions={{ headerShown: false }} />\n      </View>\n    </ConvexClientProvider>\n  );\n}\n"
  },
  {
    "path": "apps/native/src/screens/CreateNoteScreen.tsx",
    "content": "import React, { useEffect, useRef, useState } from \"react\";\nimport {\n  StyleSheet,\n  Text,\n  View,\n  Image,\n  Dimensions,\n  TouchableOpacity,\n  TextInput,\n  Keyboard,\n  Animated,\n  Alert,\n} from \"react-native\";\nimport { RFValue } from \"react-native-responsive-fontsize\";\nimport { AntDesign } from \"@expo/vector-icons\";\nimport { KeyboardAwareScrollView } from \"react-native-keyboard-aware-scroll-view\";\nimport { api } from \"@packages/backend/convex/_generated/api\";\nimport { useConvexAuth, useMutation, useQuery } from \"convex/react\";\nimport { useRouter } from \"expo-router\";\n\nconst { width } = Dimensions.get(\"window\");\n\nexport default function CreateNoteScreen() {\n  const router = useRouter();\n  const { isLoading, isAuthenticated } = useConvexAuth();\n  const createNote = useMutation(api.notes.createNote);\n  const openaiKeySet = useQuery(api.openai.openaiKeySet) ?? false;\n\n  const [isAdvancedSummarizationEnabled, setIsAdvancedSummarizationEnabled] =\n    useState(false);\n  const [noteContent, setNoteContent] = useState(\"\");\n  const [noteTitle, setNoteTitle] = useState(\"\");\n  const footerY = useRef(new Animated.Value(0)).current;\n\n  const toggleAdvancedSummarization = () => {\n    setIsAdvancedSummarizationEnabled(!isAdvancedSummarizationEnabled);\n  };\n\n  useEffect(() => {\n    const keyboardDidShowListener = Keyboard.addListener(\n      \"keyboardDidShow\",\n      () => {\n        // Slide down the footer\n        Animated.timing(footerY, {\n          toValue: 1,\n          duration: 300,\n          useNativeDriver: true,\n        }).start();\n      },\n    );\n    const keyboardDidHideListener = Keyboard.addListener(\n      \"keyboardDidHide\",\n      () => {\n        // Slide up the footer\n        Animated.timing(footerY, {\n          toValue: 0,\n          duration: 300,\n          useNativeDriver: true,\n        }).start();\n      },\n    );\n\n    // Clean up function\n    return () => {\n      keyboardDidShowListener.remove();\n      keyboardDidHideListener.remove();\n    };\n  }, [footerY]);\n\n  // Calculate the position of the footer based on the Animated.Value\n  const footerTranslateY = footerY.interpolate({\n    inputRange: [0, 1],\n    outputRange: [0, 100], // Adjust this range according to the height of your footer\n  });\n\n  const createUserNote = async () => {\n    if (!noteTitle.trim() || !noteContent.trim()) {\n      Alert.alert(\"Missing fields\", \"Please add both a title and content.\");\n      return;\n    }\n\n    if (isLoading) {\n      Alert.alert(\n        \"Please wait\",\n        \"Authenticating with backend, try again in a moment.\",\n      );\n      return;\n    }\n\n    if (!isAuthenticated) {\n      Alert.alert(\n        \"Not authenticated with backend\",\n        \"Please wait a moment or re-open the app and try again.\",\n      );\n      return;\n    }\n\n    try {\n      await createNote({\n        title: noteTitle,\n        content: noteContent,\n        isSummary: isAdvancedSummarizationEnabled,\n      });\n      router.replace(\"/\");\n    } catch (error) {\n      Alert.alert(\"Failed to create note\", String(error));\n    }\n  };\n\n  return (\n    <View style={styles.container}>\n      <View style={styles.header}>\n        <Image\n          source={require(\"../assets/icons/logo2small.png\")} // Replace with your logo image file\n          style={styles.logo}\n        />\n      </View>\n\n      <View style={styles.underHeaderContainer}>\n        <TouchableOpacity\n          onPress={() => {\n            router.back();\n          }}\n        >\n          <Image\n            style={styles.arrowBack}\n            source={require(\"../assets/icons/arrow-back.png\")}\n          />\n        </TouchableOpacity>\n\n        <Text style={styles.title}>Create a New Note</Text>\n        <TouchableOpacity>\n          <Image\n            style={styles.arrowBack}\n            source={require(\"../assets/icons/saveIcon.png\")}\n          />\n        </TouchableOpacity>\n      </View>\n\n      <KeyboardAwareScrollView\n        showsVerticalScrollIndicator={false}\n        contentContainerStyle={{ paddingBottom: 100 }}\n      >\n        <View style={styles.inputContainer}>\n          <Text style={styles.inputLabel}>Title</Text>\n          <TextInput\n            value={noteTitle}\n            onChangeText={(val: string) => setNoteTitle(val)}\n            style={styles.inputField}\n            placeholder=\"Note Title\"\n            placeholderTextColor=\"#A9A9A9\"\n          />\n          <Text style={styles.inputLabel}>Content</Text>\n          <TextInput\n            value={noteContent}\n            onChangeText={(val: string) => setNoteContent(val)}\n            style={[styles.inputField, styles.inputFieldMulti]}\n            multiline\n            placeholder=\"Note Comments\"\n            placeholderTextColor=\"#A9A9A9\"\n          />\n        </View>\n        <Text\n          style={{ ...styles.inputLabel, paddingHorizontal: 27, marginTop: 10 }}\n        >\n          AI Features\n        </Text>\n\n        {/* Advanced Summarization Section */}\n        <View style={styles.advancedSummarizationContainer}>\n          <View style={styles.advancedSummarizationCheckboxContainer}>\n            <TouchableOpacity\n              onPress={toggleAdvancedSummarization}\n              style={openaiKeySet ? styles.checkbox : styles.checkboxDisabled}\n              disabled={!openaiKeySet}\n            >\n              {isAdvancedSummarizationEnabled && (\n                <AntDesign name=\"check\" size={RFValue(12.5)} color=\"#0D87E1\" />\n              )}\n            </TouchableOpacity>\n            <Text style={styles.advancedSummarizationText}>\n              Advanced Summarization {openaiKeySet ? \"\" : \" (Disabled)\"}\n            </Text>\n          </View>\n          <Text style={styles.advancedSummarizationSubtext}>\n            {openaiKeySet\n              ? \"Check this box if you want to generate summaries using AI.\"\n              : \"Please set OPENAI_API_KEY in your environment variables.\"}\n          </Text>\n        </View>\n      </KeyboardAwareScrollView>\n      <Animated.View\n        style={[\n          styles.newNoteButtonContainer,\n          { transform: [{ translateY: footerTranslateY }] },\n        ]}\n      >\n        <TouchableOpacity onPress={createUserNote} style={styles.newNoteButton}>\n          <AntDesign name=\"plus-circle\" size={20} color=\"#fff\" />\n          <Text style={styles.newNoteButtonText}>Create a New Note</Text>\n        </TouchableOpacity>\n      </Animated.View>\n    </View>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: \"#fff\",\n  },\n  header: {\n    backgroundColor: \"#0D87E1\",\n    height: 67,\n    justifyContent: \"center\",\n    alignItems: \"center\",\n  },\n  logo: {\n    width: 46,\n    height: 46,\n    borderRadius: 20,\n    resizeMode: \"contain\",\n  },\n  underHeaderContainer: {\n    width: width,\n    height: 62,\n    backgroundColor: \"#fff\",\n    borderBottomWidth: 2,\n    borderBottomColor: \"#D9D9D9\",\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"space-between\",\n    paddingHorizontal: 16,\n  },\n  arrowBack: {\n    width: 20,\n    height: 20,\n    resizeMode: \"contain\",\n  },\n  title: {\n    fontSize: RFValue(17.5),\n    fontFamily: \"MMedium\",\n    color: \"#2D2D2D\",\n  },\n  inputContainer: {\n    paddingHorizontal: 27,\n    marginTop: 43,\n  },\n  inputLabel: {\n    fontSize: RFValue(15),\n    fontFamily: \"MMedium\",\n    color: \"#000\",\n    marginBottom: 6,\n  },\n  inputField: {\n    backgroundColor: \"#FFF\",\n    marginBottom: 30,\n    fontSize: RFValue(15),\n    fontFamily: \"MLight\",\n    color: \"#000\",\n    borderRadius: 8,\n    paddingHorizontal: 14,\n    paddingVertical: 12.5,\n    borderWidth: 1,\n    borderColor: \"#D9D9D9\",\n  },\n  inputFieldMulti: {\n    minHeight: 228,\n    textAlignVertical: \"top\",\n    paddingTop: 10,\n  },\n  advancedSummarizationContainer: {\n    paddingHorizontal: 27,\n    marginTop: 10,\n  },\n  advancedSummarizationCheckboxContainer: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    marginBottom: 8,\n  },\n  checkbox: {\n    width: RFValue(17.5),\n    height: RFValue(17.5),\n    borderRadius: RFValue(5),\n    borderWidth: 1,\n    borderColor: \"#0D87E1\",\n    justifyContent: \"center\",\n    alignItems: \"center\",\n    marginRight: RFValue(10),\n    backgroundColor: \"#F9F5FF\",\n  },\n  checkboxDisabled: {\n    width: RFValue(17.5),\n    height: RFValue(17.5),\n    borderRadius: RFValue(5),\n    borderWidth: 1,\n    borderColor: \"#D9D9D9\",\n    justifyContent: \"center\",\n    alignItems: \"center\",\n    marginRight: RFValue(10),\n    backgroundColor: \"#F9F5FF\",\n  },\n  advancedSummarizationText: {\n    fontSize: RFValue(15),\n    fontFamily: \"MLight\",\n    color: \"#000\",\n  },\n  advancedSummarizationSubtext: {\n    fontSize: RFValue(12.5),\n    fontFamily: \"MRegular\",\n    color: \"#A9A9A9\",\n    paddingHorizontal: 30,\n  },\n  newNoteButton: {\n    flexDirection: \"row\",\n    backgroundColor: \"#0D87E1\",\n    borderRadius: 7,\n    width: width / 1.6,\n    alignSelf: \"center\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    minHeight: 44,\n    position: \"absolute\",\n    bottom: 35,\n    shadowColor: \"#000\",\n    shadowOffset: {\n      width: 0,\n      height: 3,\n    },\n    shadowOpacity: 0.27,\n    shadowRadius: 4.65,\n    elevation: 6,\n  },\n  newNoteButtonText: {\n    color: \"white\",\n    fontSize: RFValue(15),\n    fontFamily: \"MMedium\",\n    marginLeft: 10,\n  },\n  newNoteButtonContainer: {\n    position: \"absolute\",\n    bottom: 0,\n    alignSelf: \"center\",\n    // ... other styles you need\n  },\n});\n"
  },
  {
    "path": "apps/native/src/screens/InsideNoteScreen.tsx",
    "content": "import React, { useState } from \"react\";\nimport { api } from \"@packages/backend/convex/_generated/api\";\nimport { useQuery } from \"convex/react\";\nimport { useLocalSearchParams, useRouter } from \"expo-router\";\nimport {\n  StyleSheet,\n  Text,\n  View,\n  Image,\n  Dimensions,\n  TouchableOpacity,\n  ScrollView,\n} from \"react-native\";\nimport { RFValue } from \"react-native-responsive-fontsize\";\n\nconst { width } = Dimensions.get(\"window\");\n\nexport default function InsideNoteScreen() {\n  const router = useRouter();\n  const { noteId } = useLocalSearchParams<{ noteId: string }>();\n  const note = useQuery(api.notes.getNote, {\n    id: noteId ?? undefined,\n  });\n  const [activeTab, setActiveTab] = useState(\"original\");\n  const noteContentText = !note\n    ? \"Note not found\"\n    : activeTab === \"original\"\n      ? note.content\n      : note.summary\n        ? note.summary\n        : \"No summary available\";\n\n  return (\n    <View style={styles.container}>\n      <View style={styles.header}>\n        <Image\n          source={require(\"../assets/icons/logo2small.png\")}\n          style={styles.logo}\n        />\n      </View>\n\n      <View style={styles.underHeaderContainer}>\n        <TouchableOpacity\n          onPress={() => {\n            router.back();\n          }}\n        >\n          <Image\n            style={styles.arrowBack}\n            source={require(\"../assets/icons/arrow-back.png\")}\n          />\n        </TouchableOpacity>\n\n        <Text style={styles.title}>{note?.title ?? \"Note\"}</Text>\n        <TouchableOpacity></TouchableOpacity>\n      </View>\n\n      <ScrollView\n        showsVerticalScrollIndicator={false}\n        contentContainerStyle={{ paddingBottom: 100 }}\n      >\n        <View style={styles.contentContainer}>\n          <Text style={styles.contentDescription}>{noteContentText}</Text>\n        </View>\n      </ScrollView>\n\n      {/* Sticky footer */}\n      <View style={styles.footer}>\n        <TouchableOpacity\n          style={[\n            styles.footerTab,\n            activeTab === \"original\" && styles.activeTab,\n          ]}\n          onPress={() => setActiveTab(\"original\")}\n        >\n          <Image\n            source={require(\"../assets/icons/OrignalIcon.png\")} // Replace with your original icon image file\n            style={[\n              styles.footerIcon,\n              activeTab === \"original\"\n                ? styles.activeIcon\n                : styles.inactiveIcon,\n            ]}\n          />\n          <Text\n            style={[\n              styles.footerText,\n              activeTab === \"original\"\n                ? styles.activeTabText\n                : styles.inactiveTabText,\n            ]}\n          >\n            Original\n          </Text>\n        </TouchableOpacity>\n        <TouchableOpacity\n          style={[\n            styles.footerTab,\n            activeTab === \"summary\" && styles.activeTab,\n          ]}\n          onPress={() => setActiveTab(\"summary\")}\n        >\n          <Image\n            source={require(\"../assets/icons/summaryIcon.png\")} // Replace with your summary icon image file\n            style={[\n              styles.footerIcon,\n              activeTab === \"summary\" ? styles.activeIcon : styles.inactiveIcon,\n            ]}\n          />\n          <Text\n            style={[\n              styles.footerText,\n              activeTab === \"summary\"\n                ? styles.activeTabText\n                : styles.inactiveTabText,\n            ]}\n          >\n            Summary\n          </Text>\n        </TouchableOpacity>\n      </View>\n    </View>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: \"#F5F7FE\",\n  },\n  header: {\n    backgroundColor: \"#0D87E1\",\n    height: 67,\n    justifyContent: \"center\",\n    alignItems: \"center\",\n  },\n  logo: {\n    width: 46,\n    height: 46,\n    borderRadius: 20,\n    resizeMode: \"contain\",\n  },\n  underHeaderContainer: {\n    width: width,\n    height: 62,\n    backgroundColor: \"#fff\",\n    borderBottomWidth: 2,\n    borderBottomColor: \"#D9D9D9\",\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"space-between\",\n    paddingHorizontal: 16,\n  },\n  arrowBack: {\n    width: 20,\n    height: 20,\n    resizeMode: \"contain\",\n  },\n  title: {\n    fontSize: RFValue(17.5),\n    fontFamily: \"MMedium\",\n    color: \"#2D2D2D\",\n  },\n  contentContainer: {\n    // Add styles for contentContainer if needed\n  },\n  contentTitle: {\n    fontSize: RFValue(17.5),\n    fontFamily: \"MMedium\",\n    color: \"#000\",\n    textAlign: \"center\",\n    marginTop: 28,\n  },\n  contentDescription: {\n    fontSize: RFValue(17.5),\n    fontFamily: \"MRegular\",\n    alignSelf: \"center\",\n    textAlign: \"justify\",\n    paddingLeft: 29,\n    paddingRight: 21,\n    marginTop: 30,\n  },\n  footer: {\n    flexDirection: \"row\",\n    position: \"absolute\",\n    bottom: 0,\n    left: 0,\n    right: 0,\n    backgroundColor: \"#fff\",\n    borderTopWidth: 1,\n    borderTopColor: \"#D9D9D9\",\n  },\n  footerTab: {\n    flex: 1,\n    padding: 12,\n    justifyContent: \"center\",\n    alignItems: \"center\",\n  },\n  footerIcon: {\n    width: 25,\n    height: 25,\n    resizeMode: \"contain\",\n  },\n  activeTab: {\n    backgroundColor: \"#0D87E1\",\n  },\n  activeIcon: {\n    tintColor: \"#fff\",\n  },\n  inactiveIcon: {\n    tintColor: \"#000\",\n  },\n  footerText: {\n    fontSize: RFValue(12.5),\n    fontFamily: \"MRegular\",\n  },\n  activeTabText: {\n    color: \"#fff\",\n  },\n  inactiveTabText: {\n    color: \"#000\",\n  },\n});\n"
  },
  {
    "path": "apps/native/src/screens/LoginScreen.tsx",
    "content": "import React from \"react\";\nimport { StyleSheet, View, Text, TouchableOpacity, Image } from \"react-native\";\nimport { useSSO } from \"@clerk/clerk-expo\";\nimport { RFValue } from \"react-native-responsive-fontsize\";\nimport { AntDesign } from \"@expo/vector-icons\";\nimport { useRouter } from \"expo-router\";\n\ntype OAuthStrategy = \"oauth_google\" | \"oauth_apple\";\n\nconst LoginScreen = () => {\n  const router = useRouter();\n  const { startSSOFlow } = useSSO();\n\n  const onPress = async ({ strategy }: { strategy: OAuthStrategy }) => {\n    try {\n      const { createdSessionId, setActive } = await startSSOFlow({ strategy });\n      if (!createdSessionId || !setActive) return;\n\n      await setActive({ session: createdSessionId });\n      router.replace(\"/\");\n    } catch (err) {\n      const message = String(err);\n      if (message.includes(\"already signed in\")) {\n        return;\n      }\n\n      console.error(\"OAuth error\", err);\n    }\n  };\n\n  return (\n    <View style={styles.container}>\n      <View style={styles.card}>\n        <Image\n          source={require(\"../assets/icons/logo.png\")} // Ensure the correct path to your logo image file\n          style={styles.logo}\n        />\n        <Text style={styles.title}>Log in to your account</Text>\n        <Text style={styles.subtitle}>Welcome! Please login below.</Text>\n        <TouchableOpacity\n          style={styles.buttonGoogle}\n          onPress={() => {\n            onPress({ strategy: \"oauth_google\" });\n          }}\n        >\n          <Image\n            style={styles.googleIcon}\n            source={require(\"../assets/icons/google.png\")}\n          />\n          <Text style={{ ...styles.buttonText, color: \"#344054\" }}>\n            Continue with Google\n          </Text>\n        </TouchableOpacity>\n\n        <TouchableOpacity\n          style={styles.buttonApple}\n          onPress={() => {\n            onPress({ strategy: \"oauth_apple\" });\n          }}\n        >\n          <AntDesign name=\"apple\" size={24} color=\"black\" />\n          <Text\n            style={{ ...styles.buttonText, color: \"#344054\", marginLeft: 12 }}\n          >\n            Continue with Apple\n          </Text>\n        </TouchableOpacity>\n\n        <View style={styles.signupContainer}>\n          <Text style={{ fontFamily: \"Regular\" }}>Don’t have an account? </Text>\n          <Text>Sign up above.</Text>\n        </View>\n      </View>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: \"#fff\",\n  },\n  card: {\n    backgroundColor: \"#fff\",\n    padding: 10,\n    alignItems: \"center\",\n    width: \"98%\",\n  },\n  logo: {\n    width: 74,\n    height: 74,\n    marginTop: 20,\n  },\n  title: {\n    marginTop: 49,\n    fontSize: RFValue(21),\n    fontFamily: \"SemiBold\",\n  },\n  subtitle: {\n    marginTop: 8,\n    fontSize: RFValue(14),\n    color: \"#000\",\n    fontFamily: \"Regular\",\n    marginBottom: 32,\n    textAlign: \"center\",\n  },\n  input: {\n    width: \"100%\",\n    borderWidth: 1,\n    borderColor: \"#D0D5DD\",\n    borderRadius: 10,\n    padding: 14,\n    marginBottom: 16,\n    fontFamily: \"Regular\",\n    fontSize: RFValue(14),\n  },\n  buttonEmail: {\n    backgroundColor: \"#0D87E1\",\n    padding: 15,\n    borderRadius: 10,\n    width: \"100%\",\n    marginBottom: 24,\n    minHeight: 44,\n  },\n  buttonText: {\n    textAlign: \"center\",\n    color: \"#FFF\",\n    fontFamily: \"SemiBold\",\n    fontSize: RFValue(14),\n  },\n  buttonTextWithIcon: {\n    marginLeft: 10,\n  },\n  dividerContainer: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    width: \"100%\",\n    marginBottom: 24,\n  },\n  divider: {\n    flex: 1,\n    height: 1,\n    backgroundColor: \"#000\",\n  },\n  dividerText: {\n    marginHorizontal: 10,\n    color: \"#000\",\n    fontFamily: \"Medium\",\n  },\n  buttonGoogle: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    backgroundColor: \"#FFF\",\n    borderRadius: 10,\n    borderWidth: 1,\n    borderColor: \"#D0D5DD\",\n    width: \"100%\",\n    marginBottom: 12,\n    height: 44,\n  },\n  buttonApple: {\n    flexDirection: \"row\",\n    justifyContent: \"center\",\n    alignItems: \"center\",\n    backgroundColor: \"#FFF\",\n    padding: 15,\n    borderRadius: 10,\n    borderWidth: 1,\n    borderColor: \"#D0D5DD\",\n    width: \"100%\",\n    marginBottom: 32,\n  },\n  signupContainer: {\n    flexDirection: \"row\",\n  },\n  signupText: {\n    color: \"#4D9DE0\",\n    fontFamily: \"SemiBold\",\n  },\n  googleIcon: {\n    width: 24,\n    height: 24,\n    marginRight: 12,\n  },\n  errorText: {\n    fontSize: RFValue(14),\n    color: \"tomato\",\n    fontFamily: \"Medium\",\n    alignSelf: \"flex-start\",\n    marginBottom: 8,\n    marginLeft: 4,\n  },\n});\n\nexport default LoginScreen;\n"
  },
  {
    "path": "apps/native/src/screens/NotesDashboardScreen.tsx",
    "content": "import React, { useState } from \"react\";\nimport {\n  StyleSheet,\n  View,\n  Text,\n  TextInput,\n  TouchableOpacity,\n  Image,\n  FlatList,\n  Dimensions,\n} from \"react-native\";\nimport { Feather, AntDesign } from \"@expo/vector-icons\";\nimport { RFValue } from \"react-native-responsive-fontsize\";\nimport { useUser } from \"@clerk/clerk-expo\";\nimport { api } from \"@packages/backend/convex/_generated/api\";\nimport { type Doc } from \"@packages/backend/convex/_generated/dataModel\";\nimport { useQuery } from \"convex/react\";\nimport { type Href, useRouter } from \"expo-router\";\n\nconst NotesDashboardScreen = () => {\n  const router = useRouter();\n  const user = useUser();\n  const imageUrl = user?.user?.imageUrl;\n  const firstName = user?.user?.firstName;\n\n  const allNotes = useQuery(api.notes.getNotes);\n  const [search, setSearch] = useState(\"\");\n\n  const finalNotes =\n    search && allNotes\n      ? allNotes.filter(\n          (note) =>\n            note.title.toLowerCase().includes(search.toLowerCase()) ||\n            note.content.toLowerCase().includes(search.toLowerCase()),\n        )\n      : (allNotes ?? []);\n\n  const renderItem = ({ item }: { item: Doc<\"notes\"> }) => (\n    <TouchableOpacity\n      onPress={() => {\n        router.push(`/notes/${item._id}` as Href);\n      }}\n      activeOpacity={0.5}\n      style={styles.noteItem}\n    >\n      <Text style={styles.noteText}>{item.title}</Text>\n    </TouchableOpacity>\n  );\n\n  return (\n    <View style={styles.container}>\n      <View style={styles.header}>\n        <Image\n          source={require(\"../assets/icons/logo2small.png\")} // Replace with your logo image file\n          style={styles.logo}\n        />\n      </View>\n\n      <View style={styles.yourNotesContainer}>\n        {/* @ts-ignore, for css purposes */}\n        <Image style={styles.avatarSmall} />\n        <Text style={styles.title}>Your Notes</Text>\n        {imageUrl ? (\n          <Image style={styles.avatarSmall} source={{ uri: imageUrl }} />\n        ) : (\n          <Text>{firstName ? firstName : \"\"}</Text>\n        )}\n      </View>\n      <View style={styles.searchContainer}>\n        <Feather\n          name=\"search\"\n          size={20}\n          color=\"grey\"\n          style={styles.searchIcon}\n        />\n        <TextInput\n          value={search}\n          onChangeText={setSearch}\n          placeholder=\"Search\"\n          style={styles.searchInput}\n        />\n      </View>\n      {!finalNotes || finalNotes.length === 0 ? (\n        <View style={styles.emptyState}>\n          <Text style={styles.emptyStateText}>\n            Create your first note to{\"\\n\"}get started\n          </Text>\n        </View>\n      ) : (\n        <FlatList\n          data={finalNotes}\n          renderItem={renderItem}\n          keyExtractor={(item) => item._id}\n          style={styles.notesList}\n          contentContainerStyle={{\n            marginTop: 19,\n            borderTopWidth: 0.5,\n            borderTopColor: \"rgba(0, 0, 0, 0.59)\",\n          }}\n        />\n      )}\n\n      <TouchableOpacity\n        onPress={() => {\n          router.push(\"/notes/new\");\n        }}\n        style={styles.newNoteButton}\n      >\n        <AntDesign name=\"plus-circle\" size={20} color=\"#fff\" />\n        <Text style={styles.newNoteButtonText}>Create a New Note</Text>\n      </TouchableOpacity>\n    </View>\n  );\n};\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: \"white\",\n  },\n  header: {\n    backgroundColor: \"#0D87E1\",\n    height: 67,\n    justifyContent: \"center\",\n    alignItems: \"center\",\n  },\n  logo: {\n    width: 46,\n    height: 46,\n    borderRadius: 20,\n    resizeMode: \"contain\",\n  },\n  title: {\n    fontSize: RFValue(17.5),\n    fontFamily: \"MMedium\",\n    alignSelf: \"center\",\n  },\n  yourNotesContainer: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"space-between\",\n    paddingHorizontal: 13,\n    marginTop: 19,\n  },\n  avatarSmall: {\n    width: 28,\n    height: 28,\n    borderRadius: 10,\n  },\n  searchContainer: {\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    borderWidth: 1,\n    borderColor: \"grey\",\n    borderRadius: 10,\n    padding: 10,\n    marginHorizontal: 15,\n    marginTop: 30,\n  },\n  searchIcon: {\n    marginRight: 10,\n  },\n  searchInput: {\n    flex: 1,\n    fontSize: RFValue(15),\n    fontFamily: \"MRegular\",\n    color: \"#2D2D2D\",\n  },\n  notesList: {\n    flex: 1,\n  },\n  noteItem: {\n    padding: 20,\n    borderBottomWidth: 0.5,\n    borderBottomColor: \"rgba(0, 0, 0, 0.59)\",\n\n    backgroundColor: \"#F9FAFB\",\n  },\n  noteText: {\n    fontSize: 16,\n    fontFamily: \"MLight\",\n    color: \"#2D2D2D\",\n  },\n\n  newNoteButton: {\n    flexDirection: \"row\",\n    backgroundColor: \"#0D87E1\",\n    borderRadius: 7,\n    width: Dimensions.get(\"window\").width / 1.6,\n    alignSelf: \"center\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    minHeight: 44,\n    position: \"absolute\",\n    bottom: 35,\n    shadowColor: \"#000\",\n    shadowOffset: {\n      width: 0,\n      height: 3,\n    },\n    shadowOpacity: 0.27,\n    shadowRadius: 4.65,\n\n    elevation: 6,\n  },\n  newNoteButtonText: {\n    color: \"white\",\n    fontSize: RFValue(15),\n    fontFamily: \"MMedium\",\n    marginLeft: 10,\n  },\n  switchContainer: {\n    position: \"absolute\",\n    top: 20,\n    right: 20,\n  },\n  emptyStateText: {\n    textAlign: \"center\",\n    alignSelf: \"center\",\n    fontSize: RFValue(15),\n    color: \"grey\",\n    fontFamily: \"MLight\",\n  },\n  emptyState: {\n    width: \"100%\",\n    height: \"35%\",\n    marginTop: 19,\n    backgroundColor: \"#F9FAFB\",\n    justifyContent: \"center\",\n    alignItems: \"center\",\n    borderWidth: 0.5,\n    borderColor: \"rgba(0, 0, 0, 0.59)\",\n  },\n});\n\nexport default NotesDashboardScreen;\n"
  },
  {
    "path": "apps/native/tsconfig.json",
    "content": "{\n  \"extends\": \"expo/tsconfig.base\",\n  \"compilerOptions\": {\n    \"strict\": true,\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\"**/*.ts\", \"**/*.tsx\", \".expo/types/**/*.ts\", \"expo-env.d.ts\"]\n}\n"
  },
  {
    "path": "apps/web/.example.env",
    "content": "NEXT_PUBLIC_CONVEX_URL=\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=\nCLERK_SECRET_KEY=\n"
  },
  {
    "path": "apps/web/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n.yarn/install-state.gz\n\n# testing\n/coverage\n\n# next.js\n/.next/\n/out/\n\n# production\n/build\n\n# misc\n.DS_Store\n*.pem\n\n# debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# local env files\n.env*.local\n\n# vercel\n.vercel\n\n# typescript\n*.tsbuildinfo\nnext-env.d.ts\n"
  },
  {
    "path": "apps/web/eslint.config.mjs",
    "content": "import { defineConfig, globalIgnores } from \"eslint/config\";\nimport nextVitals from \"eslint-config-next/core-web-vitals\";\n\nexport default defineConfig([\n  ...nextVitals,\n  globalIgnores([\".next/**\", \"out/**\", \"build/**\", \"next-env.d.ts\"]),\n]);\n"
  },
  {
    "path": "apps/web/package.json",
    "content": "{\n  \"name\": \"web-app\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"next dev\",\n    \"build\": \"next build\",\n    \"start\": \"next start\",\n    \"lint\": \"eslint .\",\n    \"typecheck\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"@clerk/nextjs\": \"^7.2.3\",\n    \"@headlessui/react\": \"^2.2.10\",\n    \"@heroicons/react\": \"^2.2.0\",\n    \"@packages/backend\": \"workspace:*\",\n    \"@radix-ui/react-avatar\": \"^1.1.11\",\n    \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n    \"@radix-ui/react-slot\": \"^1.2.4\",\n    \"class-variance-authority\": \"^0.7.1\",\n    \"convex\": \"^1.35.1\",\n    \"lucide-react\": \"^1.8.0\",\n    \"next\": \"^16.2.4\",\n    \"react\": \"^19.2.5\",\n    \"react-dom\": \"^19.2.5\",\n    \"tailwind-merge\": \"^3.5.0\"\n  },\n  \"devDependencies\": {\n    \"@eslint/eslintrc\": \"^3.3.5\",\n    \"@tailwindcss/forms\": \"0.5.11\",\n    \"@tailwindcss/postcss\": \"4.2.4\",\n    \"@types/node\": \"^25.6.0\",\n    \"@types/react\": \"19.2.14\",\n    \"@types/react-dom\": \"19.2.3\",\n    \"eslint\": \"^9.39.4\",\n    \"eslint-config-next\": \"16.2.4\",\n    \"postcss\": \"8.5.10\",\n    \"tailwindcss\": \"4.2.4\",\n    \"typescript\": \"6.0.3\"\n  }\n}\n"
  },
  {
    "path": "apps/web/postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    \"@tailwindcss/postcss\": {},\n  },\n};\n"
  },
  {
    "path": "apps/web/src/app/ConvexClientProvider.tsx",
    "content": "\"use client\";\n\nimport { type ReactNode } from \"react\";\nimport { useAuth } from \"@clerk/nextjs\";\nimport { ConvexReactClient } from \"convex/react\";\nimport { ConvexProviderWithClerk } from \"convex/react-clerk\";\n\nconst convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL;\n\nif (!convexUrl)\n  throw new Error(\"Missing NEXT_PUBLIC_CONVEX_URL for the web Convex client\");\n\nconst convex = new ConvexReactClient(convexUrl);\n\nexport default function ConvexClientProvider({\n  children,\n}: {\n  children: ReactNode;\n}) {\n  return (\n    <ConvexProviderWithClerk client={convex} useAuth={useAuth}>\n      {children}\n    </ConvexProviderWithClerk>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/app/globals.css",
    "content": "@import 'tailwindcss';\n\n@theme {\n  --breakpoint-*: initial;\n  --breakpoint-sm: 640px;\n  --breakpoint-md: 768px;\n  --breakpoint-lg: 1024px;\n  --breakpoint-xl: 1440px;\n\n  --color-primary: #0d87e1;\n\n  --font-inter: Inter, sans-serif;\n  --font-lato: Lato, sans-serif;\n  --font-montserrat: Montserrat, sans-serif;\n\n  --background-image-gradient-radial: radial-gradient(var(--tw-gradient-stops));\n  --background-image-gradient-conic: conic-gradient(\n    from 180deg at 50% 50%,\n    var(--tw-gradient-stops)\n  );\n}\n\n@utility container {\n  margin-inline: auto;\n}\n\n/*\n  The default border color has changed to `currentcolor` in Tailwind CSS v4,\n  so we've added these compatibility styles to make sure everything still\n  looks the same as it did with Tailwind CSS v3.\n\n  If we ever want to remove these styles, we need to add an explicit border\n  color utility to any element that depends on these defaults.\n*/\n@layer base {\n  *,\n  ::after,\n  ::before,\n  ::backdrop,\n  ::file-selector-button {\n    border-color: var(--color-gray-200, currentcolor);\n  }\n}\n\n.linear_gradient {\n  background: linear-gradient(\n    267deg,\n    #fff -9.43%,\n    #040218 -9.42%,\n    #fff 4.63%,\n    #d2e4f2 127.55%\n  );\n}\n\n.bg_image {\n  background:\n    linear-gradient(\n      181deg,\n      rgba(255, 255, 255, 0) 57.92%,\n      #fff 97.09%,\n      rgba(255, 255, 255, 0) 127.09%\n    ),\n    url(\"/images/background.png\"),\n    lightgray 0% 0% / 261.2499952316284px 261.2499952316284px repeat;\n}\n.button {\n  border-radius: 8px;\n  background: linear-gradient(\n    267deg,\n    #0983df -9.43%,\n    #040218 -9.42%,\n    #0d87e1 4.63%,\n    #0983df 127.55%\n  );\n  box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);\n}\n"
  },
  {
    "path": "apps/web/src/app/layout.tsx",
    "content": "import type { Metadata } from \"next\";\nimport { ClerkProvider } from \"@clerk/nextjs\";\nimport { Inter, Montserrat, Lato } from \"next/font/google\";\nimport { cn } from \"@/lib/utils\";\nimport \"./globals.css\";\nimport ConvexClientProvider from \"./ConvexClientProvider\";\n\nconst inter = Inter({ subsets: [\"latin\"] });\nconst montserrat = Montserrat({ subsets: [\"latin\"] });\nconst lato = Lato({ weight: \"400\", subsets: [\"latin\"] });\n\nexport const metadata: Metadata = {\n  title: \"Notes App\",\n  description: \"This is an app to take notes.\",\n};\n\nexport default function RootLayout({\n  children,\n}: {\n  children: React.ReactNode;\n}) {\n  return (\n    <html lang=\"en\">\n      <body\n        className={cn(inter.className, montserrat.className, lato.className)}\n      >\n        <ClerkProvider>\n          <ConvexClientProvider>{children}</ConvexClientProvider>\n        </ClerkProvider>\n      </body>\n    </html>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/app/notes/[slug]/page.tsx",
    "content": "import Header from \"@/components/Header\";\nimport NoteDetails from \"@/components/notes/NoteDetails\";\nimport { Id } from \"@packages/backend/convex/_generated/dataModel\";\n\nexport default async function Page({\n  params,\n}: {\n  params: Promise<{ slug: string }>;\n}) {\n  const { slug } = await params;\n  return (\n    <main className=\"bg-[#F5F7FE] h-screen\">\n      <Header />\n      <NoteDetails noteId={slug as Id<\"notes\">} />\n    </main>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/app/notes/page.tsx",
    "content": "import Header from \"@/components/Header\";\nimport Notes from \"@/components/notes/Notes\";\n\nexport default function Home() {\n  return (\n    <main className=\"bg-[#EDEDED] h-screen\">\n      <Header />\n      <Notes />\n    </main>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/app/page.tsx",
    "content": "\"use client\";\n\nimport Header from \"@/components/Header\";\nimport Benefits from \"@/components/home/Benefits\";\nimport Footer from \"@/components/home/Footer\";\nimport FooterHero from \"@/components/home/FooterHero\";\nimport Hero from \"@/components/home/Hero\";\nimport Testimonials from \"@/components/home/Testimonials\";\n\nexport default function Home() {\n  return (\n    <main>\n      <Header />\n      <Hero />\n      <Benefits />\n      <Testimonials />\n      <FooterHero />\n      <Footer />\n    </main>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/components/Header.tsx",
    "content": "\"use client\";\n\nimport {\n  Disclosure,\n  DisclosureButton,\n  DisclosurePanel,\n} from \"@headlessui/react\";\nimport { Bars3Icon, XMarkIcon } from \"@heroicons/react/24/outline\";\nimport { useUser } from \"@clerk/nextjs\";\nimport Link from \"next/link\";\nimport Logo from \"./common/Logo\";\nimport { UserNav } from \"./common/UserNav\";\nimport { usePathname } from \"next/navigation\";\n\ntype NavigationItem = {\n  name: string;\n  href: string;\n  current: boolean;\n};\n\nconst navigation: NavigationItem[] = [\n  { name: \"Benefits\", href: \"#Benefits\", current: true },\n  { name: \"Reviews\", href: \"#reviews\", current: false },\n];\n\nexport default function Header() {\n  const { user } = useUser();\n  const pathname = usePathname();\n\n  return (\n    <Disclosure as=\"nav\" className=\" \">\n      {({ open }) => (\n        <>\n          <div className=\"flex items-center bg-white h-16 sm:h-20\">\n            <div className=\"container px-2 sm:px-0\">\n              <div className=\"relative flex h-16 items-center justify-between\">\n                <div className=\"flex sm:hidden shrink-0 items-center\">\n                  <Logo isMobile={true} />\n                </div>\n                <div className=\"sm:flex hidden shrink-0 items-center\">\n                  <Logo />\n                </div>\n                {pathname === \"/\" && (\n                  <div className=\"flex flex-1 items-center justify-center \">\n                    <div className=\"hidden sm:ml-6 sm:block\">\n                      <ul className=\"flex space-x-28\">\n                        {navigation.map((item) => (\n                          <li key={item.name}>\n                            <Link\n                              href={item.href}\n                              className=\"text-[#2D2D2D] text-center text-xl not-italic font-normal leading-[normal]\"\n                              aria-current={item.current ? \"page\" : undefined}\n                            >\n                              {item.name}\n                            </Link>\n                          </li>\n                        ))}\n                      </ul>\n                    </div>\n                  </div>\n                )}\n                {user ? (\n                  <div className=\"hidden sm:flex absolute inset-y-0 right-0 gap-6 items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0\">\n                    <Link href=\"/notes\">\n                      <button\n                        type=\"button\"\n                        className=\" text-white text-center text-xl not-italic font-normal leading-[normal] font-montserrat px-[22px] py-[11px] button\"\n                      >\n                        See your Notes\n                      </button>\n                    </Link>\n                    <UserNav\n                      image={user?.imageUrl}\n                      name={user?.fullName ?? \"Account\"}\n                      email={user?.primaryEmailAddress?.emailAddress ?? \"\"}\n                    />\n                  </div>\n                ) : (\n                  <div className=\"hidden sm:flex absolute inset-y-0 right-0 gap-6 items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0\">\n                    <Link\n                      href=\"/notes\"\n                      className=\"border rounded-lg border-solid border-[#2D2D2D] text-[#2D2D2D] text-center text-xl not-italic font-normal leading-[normal] font-montserrat px-[22px] py-2.5\"\n                    >\n                      Sign in\n                    </Link>\n                    <Link\n                      href=\"/notes\"\n                      className=\" text-white text-center text-xl not-italic font-normal leading-[normal] font-montserrat px-[22px] py-[11px] button\"\n                    >\n                      Get Started\n                    </Link>\n                  </div>\n                )}\n                <div className=\"block sm:hidden\">\n                  {/* Mobile menu button*/}\n                  <DisclosureButton className=\"relative inline-flex  items-center justify-center rounded-md p-2 text-gray-400 focus:outline-hidden focus:ring-2 focus:ring-inset focus:ring-white\">\n                    <span className=\"absolute -inset-0.5\" />\n                    <span className=\"sr-only\">Open main menu</span>\n                    {open ? (\n                      <XMarkIcon className=\"block h-6 w-6\" aria-hidden=\"true\" />\n                    ) : (\n                      <Bars3Icon className=\"block h-6 w-6\" aria-hidden=\"true\" />\n                    )}\n                  </DisclosureButton>\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <DisclosurePanel className=\"sm:hidden\">\n            <div className=\"space-y-1 px-2 pb-3 pt-2 flex flex-col gap-3 items-start\">\n              {navigation.map((item) => (\n                <DisclosureButton\n                  key={item.name}\n                  as={Link}\n                  href={item.href}\n                  className=\"text-[#2D2D2D] text-center text-xl not-italic font-normal leading-[normal]\"\n                  aria-current={item.current ? \"page\" : undefined}\n                >\n                  {item.name}\n                </DisclosureButton>\n              ))}\n              {user ? (\n                <div className=\"flex gap-6 items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0\">\n                  <Link\n                    href=\"/notes\"\n                    className=\"text-white text-center text-xl not-italic font-normal leading-[normal] font-montserrat px-5 py-1.5 button\"\n                  >\n                    See your Notes\n                  </Link>\n                </div>\n              ) : (\n                <div className=\"flex gap-6 items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0\">\n                  <Link\n                    href=\"/notes\"\n                    className=\"border rounded-lg border-solid border-[#2D2D2D] text-[#2D2D2D] text-center text-xl not-italic font-normal leading-[normal] font-montserrat px-5 py-[5px]\"\n                  >\n                    Sign in\n                  </Link>\n                  <Link\n                    href=\"/notes\"\n                    className=\" text-white text-center text-xl not-italic font-normal leading-[normal] font-montserrat px-5 py-1.5 button\"\n                  >\n                    Get Started\n                  </Link>\n                </div>\n              )}\n            </div>\n          </DisclosurePanel>\n        </>\n      )}\n    </Disclosure>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/components/common/Logo.tsx",
    "content": "import Image from \"next/image\";\nimport Link from \"next/link\";\nimport React from \"react\";\n\ninterface Props {\n  isMobile?: boolean;\n}\n\nconst Logo = ({ isMobile }: Props) => {\n  return (\n    <Link href={\"/\"}>\n      <div className=\"flex gap-2 items-center\">\n        <Image src={\"/images/logo.png\"} width={26} height={26} alt=\"logo\" />\n        {!isMobile ? (\n          <h1 className=\"font-montserrat text-black text-3xl sm:text-[35px] not-italic font-normal leading-[90.3%] tracking-[-0.875px]\">\n            UseNotes\n          </h1>\n        ) : null}\n      </div>\n    </Link>\n  );\n};\n\nexport default Logo;\n"
  },
  {
    "path": "apps/web/src/components/common/Menu.tsx",
    "content": "import Link from \"next/link\";\n\ninterface Props {\n  menuItems: {\n    title: string;\n    url: string;\n  }[];\n}\n\nconst Menu = ({ menuItems }: Props) => {\n  return (\n    <ul className=\"flex flex-col sm:flex-row items-end sm:items-center gap-[22px] md:gap-28 \">\n      {menuItems.map((item, index) => (\n        <li key={index}>\n          <Link\n            href={item.url}\n            className=\"text-[#475467] text-base not-italic font-semibold leading-6 underline font-montserrat\"\n          >\n            {item.title}\n          </Link>\n        </li>\n      ))}\n    </ul>\n  );\n};\n\nexport default Menu;\n"
  },
  {
    "path": "apps/web/src/components/common/TestTimonialCard.tsx",
    "content": "import Image from \"next/image\";\ninterface Props {\n  data: {\n    feature?: boolean;\n    review: string;\n    profile: string;\n    name: string;\n    designation: string;\n  };\n}\n\nconst TestTimonialCard = ({ data }: Props) => {\n  return (\n    <div\n      className={`max-w-[370px] w-full space-y-8 h-auto shrink-0 rounded-[20px] border-[1.5px] border-solid border-[#EAECF0] px-[35px] pt-14 pb-20 ${\n        data.feature ? \"bg-primary\" : \"bg-white\"\n      } $}`}\n    >\n      <div className=\"flex gap-2\">\n        {Array(5)\n          .fill(0)\n          .map((data, index) => (\n            <Image\n              src=\"/images/star.svg\"\n              width={29}\n              height={29}\n              alt=\"star\"\n              key={index}\n            />\n          ))}\n      </div>\n      <blockquote\n        className={` text-lg not-italic font-normal leading-[26px] font-montserrat ${\n          data.feature ? \"text-white\" : \"text-[#313234]\"\n        }`}\n      >\n        <span className=\"text-lg\">&ldquo;</span>\n        {data.review}\n        <span className=\"text-lg\">&rdquo;</span>\n      </blockquote>\n      <div className=\"flex gap-7 items-center \">\n        <div className=\"w-[52px] h-[52px] shrink-0 border rounded-full flex items-center justify-center\">\n          <Image\n            className=\"rounded-[38px] w-[38px] h-[38px] \"\n            src={data.profile}\n            width={38}\n            height={38}\n            alt=\"ryan\"\n          />\n        </div>\n        <div className=\"\">\n          <h3\n            className={` text-xl not-italic font-medium leading-[normal] font-montserrat ${\n              data.feature ? \"text-white\" : \"text-[#25262B]\"\n            }`}\n          >\n            {data.name}\n          </h3>\n          <p\n            className={` text-base not-italic font-medium leading-[normal] font-montserrat ${\n              data.feature ? \"text-white\" : \"text-[#555F68]\"\n            }`}\n          >\n            {data.designation}\n          </p>\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default TestTimonialCard;\n"
  },
  {
    "path": "apps/web/src/components/common/UserNav.tsx",
    "content": "import { useClerk } from \"@clerk/nextjs\";\nimport { LogOut, Paintbrush2 } from \"lucide-react\";\nimport Link from \"next/link\";\nimport Image from \"next/image\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"./avatar\";\nimport { Button } from \"./button\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger,\n} from \"./dropdown-menu\";\n\nexport function UserNav({\n  image,\n  name,\n  email,\n}: {\n  image: string;\n  name: string;\n  email: string;\n}) {\n  const { signOut } = useClerk();\n\n  return (\n    <DropdownMenu>\n      <DropdownMenuTrigger asChild>\n        <Button variant=\"ghost\" className=\"relative h-10 w-10 rounded-full\">\n          <Avatar className=\"h-10 w-10\">\n            <AvatarImage src={image} alt={name} />\n            <AvatarFallback>\n              <Image\n                src=\"/images/profile.png\"\n                alt={name}\n                width={40}\n                height={40}\n              />\n            </AvatarFallback>\n          </Avatar>\n        </Button>\n      </DropdownMenuTrigger>\n      <DropdownMenuContent className=\"w-56 bg-white\" align=\"end\" forceMount>\n        <DropdownMenuLabel className=\"font-normal\">\n          <div className=\"flex flex-col space-y-1\">\n            <p className=\"text-sm font-medium leading-none text-black\">\n              {name}\n            </p>\n            <p className=\"text-xs leading-none text-black\">{email}</p>\n          </div>\n        </DropdownMenuLabel>\n        <DropdownMenuSeparator />\n        <Link href=\"/notes\">\n          <DropdownMenuItem className=\"hover:cursor-pointer hover:bg-gray-200\">\n            <Paintbrush2 className=\"mr-2 h-4 w-4 text-black\" />\n            <span className=\"text-black\">Dashboard</span>\n          </DropdownMenuItem>\n        </Link>\n        <DropdownMenuItem\n          onClick={() => {\n            signOut({ redirectUrl: \"/\" });\n          }}\n          className=\"hover:cursor-pointer hover:bg-gray-200\"\n        >\n          <LogOut className=\"mr-2 h-4 w-4 text-black\" />\n          <span className=\"text-black\">Log out</span>\n        </DropdownMenuItem>\n      </DropdownMenuContent>\n    </DropdownMenu>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/components/common/avatar.tsx",
    "content": "import * as React from \"react\";\nimport * as AvatarPrimitive from \"@radix-ui/react-avatar\";\nimport { cn } from \"@/lib/utils\";\n\nconst Avatar = React.forwardRef<\n  React.ComponentRef<typeof AvatarPrimitive.Root>,\n  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>\n>(({ className, ...props }, ref) => (\n  <AvatarPrimitive.Root\n    ref={ref}\n    className={cn(\n      \"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full\",\n      className,\n    )}\n    {...props}\n  />\n));\nAvatar.displayName = AvatarPrimitive.Root.displayName;\n\nconst AvatarImage = React.forwardRef<\n  React.ComponentRef<typeof AvatarPrimitive.Image>,\n  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>\n>(({ className, ...props }, ref) => (\n  <AvatarPrimitive.Image\n    ref={ref}\n    className={cn(\"aspect-square h-full w-full\", className)}\n    {...props}\n  />\n));\nAvatarImage.displayName = AvatarPrimitive.Image.displayName;\n\nconst AvatarFallback = React.forwardRef<\n  React.ComponentRef<typeof AvatarPrimitive.Fallback>,\n  React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>\n>(({ className, ...props }, ref) => (\n  <AvatarPrimitive.Fallback\n    ref={ref}\n    className={cn(\n      \"bg-muted flex h-full w-full items-center justify-center rounded-full\",\n      className,\n    )}\n    {...props}\n  />\n));\nAvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;\n\nexport { Avatar, AvatarImage, AvatarFallback };\n"
  },
  {
    "path": "apps/web/src/components/common/button.tsx",
    "content": "import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"bg-primary text-primary-foreground shadow-sm hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90\",\n        outline:\n          \"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground\",\n        secondary:\n          \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n        ghost: \"hover:bg-accent hover:text-accent-foreground\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2\",\n        sm: \"h-8 rounded-md px-3 text-xs\",\n        lg: \"h-10 rounded-md px-8\",\n        icon: \"h-9 w-9\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  },\n);\n\nexport interface ButtonProps\n  extends\n    React.ButtonHTMLAttributes<HTMLButtonElement>,\n    VariantProps<typeof buttonVariants> {\n  asChild?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n  ({ className, variant, size, asChild = false, ...props }, ref) => {\n    const Comp = asChild ? Slot : \"button\";\n    return (\n      <Comp\n        className={cn(buttonVariants({ variant, size, className }))}\n        ref={ref}\n        {...props}\n      />\n    );\n  },\n);\nButton.displayName = \"Button\";\n\nexport { Button, buttonVariants };\n"
  },
  {
    "path": "apps/web/src/components/common/dropdown-menu.tsx",
    "content": "import * as React from \"react\";\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nconst DropdownMenu = DropdownMenuPrimitive.Root;\n\nconst DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nconst DropdownMenuGroup = DropdownMenuPrimitive.Group;\n\nconst DropdownMenuPortal = DropdownMenuPrimitive.Portal;\n\nconst DropdownMenuSub = DropdownMenuPrimitive.Sub;\n\nconst DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {\n    inset?: boolean;\n  }\n>(({ className, inset, children, ...props }, ref) => (\n  <DropdownMenuPrimitive.SubTrigger\n    ref={ref}\n    className={cn(\n      \"focus:bg-accent data-[state=open]:bg-accent flex cursor-default select-none items-center rounded-xs px-2 py-1.5 text-sm outline-hidden\",\n      inset && \"pl-8\",\n      className,\n    )}\n    {...props}\n  >\n    {children}\n    <ChevronRight className=\"ml-auto h-4 w-4\" />\n  </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName =\n  DropdownMenuPrimitive.SubTrigger.displayName;\n\nconst DropdownMenuSubContent = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n  <DropdownMenuPrimitive.SubContent\n    ref={ref}\n    className={cn(\n      \"bg-popover text-popover-foreground z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md animate-in data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1\",\n      className,\n    )}\n    {...props}\n  />\n));\nDropdownMenuSubContent.displayName =\n  DropdownMenuPrimitive.SubContent.displayName;\n\nconst DropdownMenuContent = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n  <DropdownMenuPrimitive.Portal>\n    <DropdownMenuPrimitive.Content\n      ref={ref}\n      sideOffset={sideOffset}\n      className={cn(\n        \"bg-popover text-popover-foreground z-50 min-w-32 overflow-hidden rounded-md border p-1 shadow-md animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n        className,\n      )}\n      {...props}\n    />\n  </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;\n\nconst DropdownMenuItem = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {\n    inset?: boolean;\n  }\n>(({ className, inset, ...props }, ref) => (\n  <DropdownMenuPrimitive.Item\n    ref={ref}\n    className={cn(\n      \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-xs px-2 py-1.5 text-sm outline-hidden transition-colors data-disabled:pointer-events-none data-disabled:opacity-50\",\n      inset && \"pl-8\",\n      className,\n    )}\n    {...props}\n  />\n));\nDropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n  <DropdownMenuPrimitive.CheckboxItem\n    ref={ref}\n    className={cn(\n      \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-xs py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors data-disabled:pointer-events-none data-disabled:opacity-50\",\n      className,\n    )}\n    checked={checked}\n    {...props}\n  >\n    <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <DropdownMenuPrimitive.ItemIndicator>\n        <Check className=\"h-4 w-4\" />\n      </DropdownMenuPrimitive.ItemIndicator>\n    </span>\n    {children}\n  </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName =\n  DropdownMenuPrimitive.CheckboxItem.displayName;\n\nconst DropdownMenuRadioItem = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n  <DropdownMenuPrimitive.RadioItem\n    ref={ref}\n    className={cn(\n      \"focus:bg-accent focus:text-accent-foreground relative flex cursor-default select-none items-center rounded-xs py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors data-disabled:pointer-events-none data-disabled:opacity-50\",\n      className,\n    )}\n    {...props}\n  >\n    <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n      <DropdownMenuPrimitive.ItemIndicator>\n        <Circle className=\"h-2 w-2 fill-current\" />\n      </DropdownMenuPrimitive.ItemIndicator>\n    </span>\n    {children}\n  </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;\n\nconst DropdownMenuLabel = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {\n    inset?: boolean;\n  }\n>(({ className, inset, ...props }, ref) => (\n  <DropdownMenuPrimitive.Label\n    ref={ref}\n    className={cn(\n      \"px-2 py-1.5 text-sm font-semibold\",\n      inset && \"pl-8\",\n      className,\n    )}\n    {...props}\n  />\n));\nDropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;\n\nconst DropdownMenuSeparator = React.forwardRef<\n  React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n  React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n  <DropdownMenuPrimitive.Separator\n    ref={ref}\n    className={cn(\"bg-muted -mx-1 my-1 h-px\", className)}\n    {...props}\n  />\n));\nDropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;\n\nconst DropdownMenuShortcut = ({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n  return (\n    <span\n      className={cn(\"ml-auto text-xs tracking-widest opacity-60\", className)}\n      {...props}\n    />\n  );\n};\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\";\n\nexport {\n  DropdownMenu,\n  DropdownMenuTrigger,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuCheckboxItem,\n  DropdownMenuRadioItem,\n  DropdownMenuLabel,\n  DropdownMenuSeparator,\n  DropdownMenuShortcut,\n  DropdownMenuGroup,\n  DropdownMenuPortal,\n  DropdownMenuSub,\n  DropdownMenuSubContent,\n  DropdownMenuSubTrigger,\n  DropdownMenuRadioGroup,\n};\n"
  },
  {
    "path": "apps/web/src/components/home/Benefits.tsx",
    "content": "import Image from \"next/image\";\n\nconst benefits = [\n  {\n    title: \"Effortless Note-Taking\",\n    description: \"Capture thoughts effortlessly with our intuitive interface\",\n    image: \"/images/goodNews.png\",\n  },\n  {\n    title: \"Seamless Sync\",\n    description:\n      \"Access your notes anytime, anywhere, with seamless cloud synchronization.\",\n    image: \"/images/cloudSync.png\",\n  },\n  {\n    title: \"Enhanced Productivity\",\n    description:\n      \"Let AI handle organization, so you can focus on what matters most.\",\n    image: \"/images/googleCalander.png\",\n  },\n  {\n    title: \"AI-Powered Insights\",\n    description:\n      \"Gain valuable insights with smart analytics based on your note patterns.\",\n    image: \"/images/bot.png\",\n  },\n];\n\nconst Benefits = () => {\n  return (\n    <section id=\"Benefits\" className=\"relative pointer-events-none\">\n      <Image\n        src={\"/images/blue-circle.svg\"}\n        width={503}\n        height={531}\n        alt=\"\"\n        className=\"absolute hidden sm:block -left-40 -top-48 h-[531px]\"\n      />\n      <div className=\"container py-16 px-2 md:px-0\">\n        <p className=\"text-black text-[17px] sm:text-3xl not-italic font-medium leading-[90.3%] tracking-[-0.75px] text-center font-montserrat pb-2 sm:pb-[18px]\">\n          Benefits\n        </p>\n        <h3 className=\" text-black text-3xl sm:text-[57px] not-italic font-medium leading-[90.3%] tracking-[-1.425px] font-montserrat text-center pb-[46px] sm:pb-[87px]\">\n          Why Choose UseNotes\n        </h3>\n\n        <div className=\"relative\">\n          <div className=\"hidden sm:flex justify-between items-center absolute inset-0 -z-10\">\n            {Array(3)\n              .fill(0)\n              .map((_, index) => (\n                <Image\n                  src=\"/images/cricle.svg\"\n                  width={183}\n                  height={193}\n                  alt=\"line\"\n                  key={index}\n                />\n              ))}\n          </div>\n\n          <div className=\"grid grid-cols-1 lg:grid-cols-2 gap-8 z-10 \">\n            {benefits.map((benefit, index) => (\n              <div\n                key={index}\n                className=\"flex gap-2 sm:gap-7 bg-white items-center border rounded-[17px] py-4 px-2 sm:py-12 sm:px-6 border-solid border-[#B8B5B5] shadow-xl\"\n              >\n                <div className=\" min-w-16 sm:min-w-28\">\n                  <Image\n                    src={benefit.image}\n                    width={100}\n                    height={100}\n                    alt=\"benefit\"\n                    className=\"sm:w-[100px] w-[58px]\"\n                  />\n                </div>\n                <div className=\"\">\n                  <h4 className=\"text-black text-[24px] sm:text-[42px] not-italic font-medium leading-[90.3%] tracking-[-1.05px] pb-2 sm:pb-6 font-montserrat\">\n                    {benefit.title}\n                  </h4>\n                  <p className=\"font-montserrat pb-2 text-black text-[17px] sm:text-3xl not-italic font-normal leading-[90.3%] tracking-[-0.75px]\">\n                    {benefit.description}\n                  </p>\n                </div>\n              </div>\n            ))}\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nexport default Benefits;\n"
  },
  {
    "path": "apps/web/src/components/home/ComplexToggle.tsx",
    "content": "import { useState } from \"react\";\nimport { Switch } from \"@headlessui/react\";\n\nfunction classNames(...classes: string[]) {\n  return classes.filter(Boolean).join(\" \");\n}\n\nexport default function ComplexToggle({\n  setIsSummary,\n  isSummary,\n}: {\n  setIsSummary: (value: boolean) => void;\n  isSummary: boolean;\n}) {\n  return (\n    <Switch.Group as=\"div\" className=\"flex items-center\">\n      <Switch.Label as=\"span\" className=\"mr-3 text-sm\">\n        <span\n          className={`text-gray-900 ${\n            !isSummary ? \"font-bold\" : \"font-medium\"\n          }`}\n        >\n          Original Note\n        </span>{\" \"}\n      </Switch.Label>\n      <Switch\n        checked={isSummary}\n        onChange={setIsSummary}\n        className={classNames(\n          isSummary ? \"bg-primary\" : \"bg-gray-200\",\n          \"relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-hidden \",\n        )}\n      >\n        <span\n          aria-hidden=\"true\"\n          className={classNames(\n            isSummary ? \"translate-x-5\" : \"translate-x-0\",\n            \"pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow-sm ring-0 transition duration-200 ease-in-out\",\n          )}\n        />\n      </Switch>\n      <Switch.Label as=\"span\" className=\"ml-3 text-sm\">\n        <span\n          className={`text-gray-900 ${isSummary ? \"font-bold\" : \"font-medium\"}`}\n        >\n          AI Summary\n        </span>{\" \"}\n      </Switch.Label>\n    </Switch.Group>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/components/home/Footer.tsx",
    "content": "import React from \"react\";\nimport Logo from \"../common/Logo\";\nimport Menu from \"../common/Menu\";\n\nconst menuItems = [\n  {\n    title: \"Home\",\n    url: \"/\",\n  },\n  {\n    title: \"Benefits\",\n    url: \"#Benefits\",\n  },\n  {\n    title: \"Get Started\",\n    url: \"/notes\",\n  },\n  {\n    title: \"Reviews\",\n    url: \"#reviews\",\n  },\n];\n\nconst Footer = () => {\n  return (\n    <>\n      <div className=\"container hidden sm:block py-12\">\n        <div className=\"flex flex-wrap md:flex-nowrap justify-between items-center pb-6\">\n          <Logo />\n          <Menu menuItems={menuItems} />\n        </div>\n        <div className=\"pt-8 border-t-[#929292] border-t border-solid\">\n          <h3 className=\"text-gray-900 text-xl not-italic font-semibold leading-[30px] font-montserrat pb-2\">\n            Take more efficient notes with UseNotes\n          </h3>\n          <div className=\"flex justify-between\">\n            <p className=\"text-gray-600 font-montserrat text-base not-italic font-normal leading-6\">\n              Save countless hours of note-taking and organize your notes\n              easier.\n            </p>\n            <p className=\"text-gray-600 font-inter text-base not-italic font-normal leading-6\">\n              © 2023 UseNotes. All rights reserved.\n            </p>\n          </div>\n        </div>\n      </div>\n\n      <div className=\"container sm:hidden pt-7 pl-6 pr-5\">\n        <div className=\"flex justify-between items-center\">\n          <div className=\"flex flex-col gap-6\">\n            <Logo />\n            <h3 className=\"text-[#101828] text-base not-italic font-semibold leading-[18px] font-montserrat\">\n              Take more efficient notes with UseNotes\n            </h3>\n            <p className=\"text-[#101828] font-montserrat text-base not-italic font-light leading-[18px]\">\n              Save countless hours of note-taking and organize your notes\n              easier.\n            </p>\n          </div>\n          <div className=\"min-w-[100px]\">\n            <Menu menuItems={menuItems} />\n          </div>\n        </div>\n        <p className=\"text-[#667085] font-inter text-center text-base not-italic font-light leading-[18px] py-11\">\n          © 2023 UseNotes. All rights reserved. <br />\n          <span className=\"mt-1\"> Icons by Icons8</span>\n        </p>\n      </div>\n    </>\n  );\n};\n\nexport default Footer;\n"
  },
  {
    "path": "apps/web/src/components/home/FooterHero.tsx",
    "content": "import Image from \"next/image\";\nimport Link from \"next/link\";\nimport React from \"react\";\n\nconst FooterHero = () => {\n  return (\n    <div className=\"bg-primary\">\n      <div className=\"flex flex-wrap md:flex-nowrap justify-between container py-20 px-6 sm:px-0\">\n        <div className=\"max-w-[802px]\">\n          <h2 className=\"font-montserrat text-wrap text-white not-italic text-3xl md:text-[57px] font-semibold sm:leading-[109.3%] sm:tracking-[-1.425px] leading-[97.3%] tracking-[-0.75px] pb-[31px] sm:pb-[38px]\">\n            Start Your Intelligent Note-Taking Journey\n          </h2>\n          <p className=\"text-white max-w-[681px] text-xl sm:text-3xl not-italic font-normal leading-[103.3%] tracking-[-0.75px] font-montserrat pb-[66px] sm:pb-[53px]\">\n            Sign up now and experience the power of AI-enhanced note-taking with\n            UseNotes\n          </p>\n          <Link href={\"/notes\"}>\n            <button className=\"linear_gradient flex max-w-[438px] w-full justify-center items-center gap-2.5 shadow-[0px_4px_4px_0px_rgba(0,0,0,0.25)] px-8 py-4 rounded-[11px]  text-black text-xl sm:text-3xl not-italic font-semibold leading-[90.3%] tracking-[-0.75px]\">\n              Get Started For Free\n            </button>\n          </Link>\n        </div>\n        <div className=\"mt-20 md:mt-0\">\n          <Image\n            src=\"/images/monitor.png\"\n            alt=\"hero\"\n            width={560}\n            height={456}\n          />\n        </div>\n      </div>\n    </div>\n  );\n};\n\nexport default FooterHero;\n"
  },
  {
    "path": "apps/web/src/components/home/Hero.tsx",
    "content": "import Image from \"next/image\";\nimport Link from \"next/link\";\n\nconst Hero = () => {\n  return (\n    <section className=\"bg_image\">\n      <div className=\"container py-16 sm:py-36 px-6 sm:px-0\">\n        <div className=\"flex sm:flex-wrap flex-nowrap justify-between items-center max-h-[690px] h-full\">\n          <div className=\"\">\n            <h2 className=\"font-montserrat pb-7 sm:pb-[26px] text-black text-[44px] sm:text-[75px] not-italic font-medium leading-[111.3%] tracking-[-1.1px] sm:tracking-[-1.875px]\">\n              The Ultimate <br /> Note-Taking Experience\n            </h2>\n            <p className=\"font-montserrat sm:pb-16 max-w-[680px] text-black text-xl sm:text-3xl not-italic font-normal leading-[103.3%] tracking-[-0.5px] sm:tracking-[-0.75px] pb-11\">\n              UseNotes harnesses the power of artificial intelligence to\n              revolutionize the way you capture, organize, and recall your\n              thoughts\n            </p>\n            <Link href={\"/notes\"}>\n              <button className=\"button gap-2.5 px-8 py-4 font-montserrat text-white text-xl sm:text-3xl not-italic font-semibold leading-[90.3%] tracking-[-0.5px] sm:tracking-[-0.75px]\">\n                Get Started\n              </button>\n            </Link>\n          </div>\n          <div className=\"max-w-[570px] w-full h-full\">\n            <div className=\"relative max-w-[570px] w-full h-[380px] sm:h-[680px]\">\n              <div className=\"absolute z-10 inset-0 flex justify-center items-center bg-[#0983DF99] opacity-40 blur-[102px] rounded-[673px]\">\n                <Image\n                  src={\"/images/hero_image_bg.svg\"}\n                  width={541}\n                  height={673}\n                  alt=\"hero\"\n                  className=\"w-[344px] sm:w-[541px] \"\n                />\n              </div>\n              <div className=\" absolute z-50 inset-0 flex justify-center items-center\">\n                <Image\n                  src={\"/images/hero.png\"}\n                  width={561}\n                  height={456}\n                  alt=\"hero\"\n                  className=\"w-[357px] sm:w-[561px]\"\n                />\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </section>\n  );\n};\n\nexport default Hero;\n"
  },
  {
    "path": "apps/web/src/components/home/Testimonials.tsx",
    "content": "import Image from \"next/image\";\nimport TestTimonialCard from \"../common/TestTimonialCard\";\n\nconst TestimonialsData = [\n  {\n    rating: 5,\n    review:\n      \"Great note-taking application! The AI features make note-taking a breeze\",\n    name: \"Ryan Lowry\",\n    designation: \"Engineer & Author\",\n    profile: \"/images/profile.png\",\n    feature: false,\n  },\n  {\n    rating: 5,\n    review:\n      \"Really like the clean design of UseNotes. The AI-driven search is impressively accurate, adding a personal dimension to my notes. Fast and very easy to use.\",\n    name: \"John Collins\",\n    designation: \"Engineer & Author\",\n    profile: \"/images/profile.png\",\n    feature: true,\n  },\n  {\n    rating: 5,\n    review: \"Simply brilliant! UseNotes has elevated my productivity.\",\n    name: \"Moe Partuj\",\n    designation: \"Student\",\n    profile: \"/images/Moe-Partuj.jpeg\",\n    feature: false,\n  },\n];\n\nconst Testimonials = () => {\n  return (\n    <section\n      id=\"reviews\"\n      className=\"bg_image bg_circle relative overflow-hidden\"\n    >\n      <Image\n        src={\"/images/blue-circle-right.svg\"}\n        width={503}\n        height={531}\n        alt=\"\"\n        className=\"absolute hidden sm:block -right-40 top-1/4 h-[531px]\"\n      />\n      <div className=\"container py-11 sm:py-16 px-6 sm:px-0\">\n        <p className=\"text-black text-[17px] sm:text-3xl not-italic font-medium leading-[90.3%] tracking-[-0.75px] text-center font-montserrat pb-2 sm:pb-[18px]\">\n          Reviews\n        </p>\n        <h3 className=\" text-black text-3xl sm:text-[57px] not-italic font-medium leading-[90.3%] tracking-[-1.425px] font-montserrat text-center pb-[20px] sm:pb-[87px]\">\n          User Testimonials\n        </h3>\n\n        <div className=\"flex flex-wrap md:flex-nowrap justify-center items-start gap-4 pb-10 mb-10 relative\">\n          <Image\n            src={\"/images/message-left.svg\"}\n            width={110}\n            height={102}\n            alt=\"\"\n            className=\"absolute hidden md:block left-0 top-full\"\n          />\n          <Image\n            src={\"/images/message-right.svg\"}\n            width={110}\n            height={102}\n            alt=\"\"\n            className=\"absolute hidden md:block right-0 bottom-full\"\n          />\n          {TestimonialsData.map((item, index) => (\n            <TestTimonialCard data={item} key={index} />\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n};\n\nexport default Testimonials;\n"
  },
  {
    "path": "apps/web/src/components/notes/Checkbox.tsx",
    "content": "const Checkbox = ({\n  isChecked,\n  checkHandler,\n  openaiKeySet,\n}: {\n  isChecked: boolean;\n  checkHandler: () => void;\n  openaiKeySet: boolean;\n}) => {\n  return (\n    <div className=\"relative flex  gap-x-3\">\n      <div className=\"flex items-start mt-[5px]\">\n        <input\n          id=\"candidates\"\n          name=\"candidates\"\n          type=\"checkbox\"\n          checked={isChecked}\n          onChange={checkHandler}\n          className=\"accent-white checked:accent-white w-5 h-5 focus:ring-0 focus:outline-0  border-[#0D87E1] rounded-[6px] bg-[#F9F5FF]\"\n          disabled={!openaiKeySet}\n        />\n      </div>\n      <div className=\"\">\n        <label\n          htmlFor=\"candidates\"\n          className=\" text-black text-[17px] sm:text-2xl pb-2 not-italic font-light leading-[90.3%] tracking-[-0.6px]\"\n        >\n          Advanced Summarization {openaiKeySet ? \"\" : \" (Disabled)\"}\n        </label>\n        {openaiKeySet ? (\n          <p className=\" text-black text-sm sm:text-[17px] not-italic font-extralight leading-[90.3%] tracking-[-0.425px]\">\n            Check this box if you want to generate summaries using AI\n          </p>\n        ) : (\n          <p>\n            <a\n              className=\"text-blue-500\"\n              target=\"_blank\"\n              href=\"https://dashboard.convex.dev/deployment/settings/environment-variables?var=OPENAI_API_KEY\"\n            >\n              Set an OPENAI_API_KEY in your environment variables here.\n            </a>\n          </p>\n        )}\n      </div>\n    </div>\n  );\n};\n\nexport default Checkbox;\n"
  },
  {
    "path": "apps/web/src/components/notes/CreateNote.tsx",
    "content": "\"use client\";\n\nimport { Fragment, useRef, useState } from \"react\";\nimport { Dialog, Transition } from \"@headlessui/react\";\nimport Image from \"next/image\";\nimport Checkbox from \"./Checkbox\";\nimport { api } from \"@packages/backend/convex/_generated/api\";\nimport { useMutation, useQuery } from \"convex/react\";\n\nexport default function CreateNote() {\n  const [open, setOpen] = useState(false);\n  const [title, setTitle] = useState(\"\");\n  const [content, setContent] = useState(\"\");\n  const [isChecked, setIsChecked] = useState<boolean>(false);\n\n  const cancelButtonRef = useRef(null);\n\n  const createNote = useMutation(api.notes.createNote);\n  const openaiKeySet = useQuery(api.openai.openaiKeySet) ?? true;\n\n  const createUserNote = async () => {\n    await createNote({\n      title,\n      content,\n      isSummary: isChecked,\n    });\n    setOpen(false);\n  };\n\n  return (\n    <>\n      <div className=\"flex justify-center items-center\">\n        <button\n          onClick={() => setOpen(true)}\n          className=\"button text-[#EBECEF] flex gap-4 justify-center items-center text-center px-8 sm:px-16 py-2\"\n        >\n          <Image\n            src={\"/images/Add.png\"}\n            width={40}\n            height={40}\n            alt=\"search\"\n            className=\"float-right sm:w-[40px] sm:h-[40px] w-6 h-6\"\n          />\n          <span className=\"text-[17px] sm:text-3xl not-italic font-medium leading-[79%] tracking-[-0.75px]\">\n            {\" \"}\n            New Note\n          </span>\n        </button>\n      </div>\n\n      <Transition.Root show={open} as={Fragment}>\n        <Dialog\n          as=\"div\"\n          className=\"relative z-10\"\n          initialFocus={cancelButtonRef}\n          onClose={setOpen}\n        >\n          <Transition.Child\n            as={Fragment}\n            enter=\"ease-out duration-300\"\n            enterFrom=\"opacity-0\"\n            enterTo=\"opacity-100\"\n            leave=\"ease-in duration-200\"\n            leaveFrom=\"opacity-100\"\n            leaveTo=\"opacity-0\"\n          >\n            <div className=\"fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity\" />\n          </Transition.Child>\n\n          <form className=\"fixed inset-0 z-10 w-screen overflow-y-auto\">\n            <div className=\"flex min-h-full items-end justify-center p-2 text-center sm:items-center sm:p-0\">\n              <Transition.Child\n                as={Fragment}\n                enter=\"ease-out duration-300\"\n                enterFrom=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n                enterTo=\"opacity-100 translate-y-0 sm:scale-100\"\n                leave=\"ease-in duration-200\"\n                leaveFrom=\"opacity-100 translate-y-0 sm:scale-100\"\n                leaveTo=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n              >\n                <Dialog.Panel className=\"relative transform overflow-hidden rounded-[10px] bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-[719px]\">\n                  <div className=\"bg-white px-4 pb-4 pt-5 sm:p-8 sm:pb-4\">\n                    <>\n                      <div className=\"mt-3  sm:mt-0 text-left\">\n                        <Dialog.Title\n                          as=\"h3\"\n                          className=\"text-black text-center text-xl sm:text-left sm:text-[35px] pb-6 sm:pb-8 not-italic font-semibold leading-[90.3%] tracking-[-0.875px]\"\n                        >\n                          Create New Note\n                        </Dialog.Title>\n                        <div className=\"mt-2 space-y-3\">\n                          <div className=\"pb-2\">\n                            <label\n                              htmlFor=\"title\"\n                              className=\" text-black text-[17px] sm:text-2xl not-italic font-medium leading-[90.3%] tracking-[-0.6px]\"\n                            >\n                              Title\n                            </label>\n                            <div className=\"mt-2\">\n                              <input\n                                id=\"title\"\n                                name=\"title\"\n                                type=\"text\"\n                                placeholder=\"Note Title\"\n                                autoComplete=\"title\"\n                                value={title}\n                                onChange={(e) => setTitle(e.target.value)}\n                                className=\"border shadow-[0px_1px_2px_0px_rgba(16,24,40,0.05)] rounded-lg border-solid border-[#D0D5DD] bg-white w-full py-2.5 px-[14px] text-black text-[17px] not-italic font-light leading-[90.3%] tracking-[-0.425px] sm:text-2xl\"\n                              />\n                            </div>\n                          </div>\n\n                          <div className=\"\">\n                            <label\n                              htmlFor=\"description\"\n                              className=\" text-black text-[17px] sm:text-2xl not-italic font-medium leading-[90.3%] tracking-[-0.6px]\"\n                            >\n                              The Note\n                            </label>\n                            <div className=\"mt-2 pb-[18px]\">\n                              <textarea\n                                id=\"description\"\n                                name=\"description\"\n                                rows={8}\n                                placeholder=\"Start your note \"\n                                className=\"block w-full rounded-md border-0 py-1.5  border-[#D0D5DD] text-2xl shadow-xs ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600  sm:leading-6 text-black text-[17px] not-italic font-light leading-[90.3%] tracking-[-0.425px] sm:text-2xl\"\n                                value={content}\n                                onChange={(e) => setContent(e.target.value)}\n                              />\n                            </div>\n                            <p className=\"text-black text-[17px] sm:text-2xl not-italic font-medium leading-[90.3%] tracking-[-0.6px]\">\n                              AI Features\n                            </p>\n                          </div>\n\n                          <Checkbox\n                            openaiKeySet={openaiKeySet}\n                            isChecked={isChecked}\n                            checkHandler={() => setIsChecked(!isChecked)}\n                          />\n                        </div>\n                      </div>\n                    </>\n                  </div>\n                  <div className=\" px-4 py-3 mb-5 flex justify-center items-center\">\n                    <button\n                      type=\"button\"\n                      className=\"button text-white text-center text-[17px] sm:text-2xl not-italic font-semibold leading-[90.3%] tracking-[-0.6px] px-[70px] py-2\"\n                      onClick={createUserNote}\n                    >\n                      Create\n                    </button>\n                  </div>\n                </Dialog.Panel>\n              </Transition.Child>\n            </div>\n          </form>\n        </Dialog>\n      </Transition.Root>\n    </>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/components/notes/DeleteNote.tsx",
    "content": "\"use client\";\nimport { Fragment, useRef, useState } from \"react\";\nimport { Dialog, Transition } from \"@headlessui/react\";\nimport { ExclamationTriangleIcon } from \"@heroicons/react/24/outline\";\nimport Image from \"next/image\";\n\nexport default function DeleteNote({ deleteAction }: any) {\n  const [open, setOpen] = useState(false);\n\n  const cancelButtonRef = useRef(null);\n\n  return (\n    <>\n      <Image\n        onClick={() => setOpen(true)}\n        src={\"/images/delete.svg\"}\n        width={20}\n        height={20}\n        alt=\"search\"\n        className=\"cursor-pointer\"\n      />\n\n      <Transition.Root show={open} as={Fragment}>\n        <Dialog\n          as=\"div\"\n          className=\"relative z-10\"\n          initialFocus={cancelButtonRef}\n          onClose={setOpen}\n        >\n          <Transition.Child\n            as={Fragment}\n            enter=\"ease-out duration-300\"\n            enterFrom=\"opacity-0\"\n            enterTo=\"opacity-100\"\n            leave=\"ease-in duration-200\"\n            leaveFrom=\"opacity-100\"\n            leaveTo=\"opacity-0\"\n          >\n            <div className=\"fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity\" />\n          </Transition.Child>\n\n          <div className=\"fixed inset-0 z-10 w-screen overflow-y-auto\">\n            <div className=\"flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0\">\n              <Transition.Child\n                as={Fragment}\n                enter=\"ease-out duration-300\"\n                enterFrom=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n                enterTo=\"opacity-100 translate-y-0 sm:scale-100\"\n                leave=\"ease-in duration-200\"\n                leaveFrom=\"opacity-100 translate-y-0 sm:scale-100\"\n                leaveTo=\"opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95\"\n              >\n                <Dialog.Panel className=\"relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg\">\n                  <div className=\"bg-white px-4 pb-4 pt-5 sm:p-6 sm:pb-4\">\n                    <div className=\"sm:flex sm:items-start\">\n                      <div className=\"mx-auto flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-red-100 sm:mx-0 sm:h-10 sm:w-10\">\n                        <ExclamationTriangleIcon\n                          className=\"h-6 w-6 text-red-600\"\n                          aria-hidden=\"true\"\n                        />\n                      </div>\n                      <div className=\"mt-3 text-center sm:ml-4 sm:mt-0 sm:text-left\">\n                        <Dialog.Title\n                          as=\"h3\"\n                          className=\"text-base font-semibold leading-6 text-gray-900\"\n                        >\n                          Delete Note\n                        </Dialog.Title>\n                        <div className=\"mt-2\">\n                          <p className=\"text-sm text-gray-500\">\n                            Are you sure you want to delete this note? All of\n                            your data will be permanently removed. This action\n                            cannot be undone.\n                          </p>\n                        </div>\n                      </div>\n                    </div>\n                  </div>\n                  <div className=\"bg-gray-50 px-4 py-3 sm:flex sm:flex-row-reverse sm:px-6\">\n                    <button\n                      type=\"button\"\n                      className=\"inline-flex w-full justify-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-xs hover:bg-red-500 sm:ml-3 sm:w-auto\"\n                      onClick={() => {\n                        deleteAction();\n                        setOpen(false);\n                      }}\n                    >\n                      Delete\n                    </button>\n                    <button\n                      type=\"button\"\n                      className=\"mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-xs ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:mt-0 sm:w-auto\"\n                      onClick={() => setOpen(false)}\n                      ref={cancelButtonRef}\n                    >\n                      Cancel\n                    </button>\n                  </div>\n                </Dialog.Panel>\n              </Transition.Child>\n            </div>\n          </div>\n        </Dialog>\n      </Transition.Root>\n    </>\n  );\n}\n"
  },
  {
    "path": "apps/web/src/components/notes/NoteDetails.tsx",
    "content": "\"use client\";\n\nimport { api } from \"@packages/backend/convex/_generated/api\";\nimport { Id } from \"@packages/backend/convex/_generated/dataModel\";\nimport { useQuery } from \"convex/react\";\nimport ComplexToggle from \"../home/ComplexToggle\";\nimport { useState } from \"react\";\n\ninterface NoteDetailsProps {\n  noteId: Id<\"notes\">;\n}\n\nconst NoteDetails = ({ noteId }: NoteDetailsProps) => {\n  const [isSummary, setIsSummary] = useState(false);\n  const currentNote = useQuery(api.notes.getNote, { id: noteId });\n\n  return (\n    <div className=\"container space-y-6 sm:space-y-9 py-20 px-[26px] sm:px-0\">\n      <div className=\"flex justify-center items-center\">\n        <ComplexToggle isSummary={isSummary} setIsSummary={setIsSummary} />\n      </div>\n      <h3 className=\"text-black text-center pb-5 text-xl sm:text-[32px] not-italic font-semibold leading-[90.3%] tracking-[-0.8px]\">\n        {currentNote?.title}\n      </h3>\n      <p className=\"text-black text-xl sm:text-[28px] not-italic font-normal leading-[130.3%] tracking-[-0.7px]\">\n        {!isSummary\n          ? currentNote?.content\n          : currentNote?.summary\n            ? currentNote?.summary\n            : \"No Summary available\"}\n      </p>\n    </div>\n  );\n};\n\nexport default NoteDetails;\n"
  },
  {
    "path": "apps/web/src/components/notes/NoteItem.tsx",
    "content": "import Link from \"next/link\";\nimport DeleteNote from \"./DeleteNote\";\n\nexport interface NoteProps {\n  note: {\n    title: string;\n    _id: string;\n    _creationTime: number;\n  };\n  deleteNote: any;\n}\n\nconst NoteItem = ({ note, deleteNote }: NoteProps) => {\n  return (\n    <div className=\"flex justify-between items-center h-[74px] bg-[#F9FAFB] py-5 px-5 sm:px-11 gap-x-5 sm:gap-x-10\">\n      <Link href={`/notes/${note._id}`} className=\"flex-1\">\n        <h1 className=\" text-[#2D2D2D] text-[17px] sm:text-2xl not-italic font-normal leading-[114.3%] tracking-[-0.6px]\">\n          {note.title}\n        </h1>\n      </Link>\n      <p className=\"hidden md:flex text-[#2D2D2D] text-center text-xl not-italic font-extralight leading-[114.3%] tracking-[-0.5px]\">\n        {new Date(Number(note._creationTime)).toLocaleDateString()}\n      </p>\n      <DeleteNote deleteAction={() => deleteNote({ noteId: note._id })} />\n    </div>\n  );\n};\n\nexport default NoteItem;\n"
  },
  {
    "path": "apps/web/src/components/notes/Notes.tsx",
    "content": "\"use client\";\n\nimport { api } from \"@packages/backend/convex/_generated/api\";\nimport { useMutation, useQuery } from \"convex/react\";\nimport Image from \"next/image\";\nimport { useState } from \"react\";\nimport CreateNote from \"./CreateNote\";\nimport NoteItem from \"./NoteItem\";\n\nconst Notes = () => {\n  const [search, setSearch] = useState(\"\");\n\n  const allNotes = useQuery(api.notes.getNotes);\n  const deleteNote = useMutation(api.notes.deleteNote);\n\n  const finalNotes = search\n    ? allNotes?.filter(\n        (note) =>\n          note.title.toLowerCase().includes(search.toLowerCase()) ||\n          note.content.toLowerCase().includes(search.toLowerCase()),\n      )\n    : allNotes;\n\n  return (\n    <div className=\"container pb-10\">\n      <h1 className=\"text-[#2D2D2D] text-center text-[20px] sm:text-[43px] not-italic font-normal sm:font-medium leading-[114.3%] tracking-[-1.075px] sm:mt-8 my-4  sm:mb-10\">\n        Your Notes\n      </h1>\n      <div className=\"px-5 sm:px-0\">\n        <div className=\"bg-white flex items-center h-[39px] sm:h-[55px] rounded-sm border border-solid gap-2 sm:gap-5 mb-10 border-[rgba(0,0,0,0.40)] px-3 sm:px-11\">\n          <Image\n            src={\"/images/search.svg\"}\n            width={23}\n            height={22}\n            alt=\"search\"\n            className=\"cursor-pointer sm:w-[23px] sm:h-[22px] w-[20px] h-[20px]\"\n          />\n          <input\n            type=\"text\"\n            placeholder=\"Search\"\n            value={search}\n            onChange={(e) => setSearch(e.target.value)}\n            className=\"flex-1 text-[#2D2D2D] text-[17px] sm:text-2xl not-italic font-light leading-[114.3%] tracking-[-0.6px] focus:outline-0 focus:ring-0 focus:border-0 border-0\"\n          />\n        </div>\n      </div>\n\n      <div className=\"border-[0.5px] mb-20 divide-y-[0.5px] divide-[#00000096] border-[#00000096]\">\n        {finalNotes &&\n          finalNotes.map((note) => (\n            <NoteItem key={note._id} note={note} deleteNote={deleteNote} />\n          ))}\n      </div>\n\n      <CreateNote />\n    </div>\n  );\n};\n\nexport default Notes;\n"
  },
  {
    "path": "apps/web/src/lib/utils.ts",
    "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"
  },
  {
    "path": "apps/web/src/proxy.ts",
    "content": "import { clerkMiddleware, createRouteMatcher } from \"@clerk/nextjs/server\";\n\nconst isProtectedRoute = createRouteMatcher([\"/notes(.*)\"]);\n\nexport default clerkMiddleware(async (auth, request) => {\n  if (!isProtectedRoute(request)) return;\n\n  await auth.protect();\n});\n\nexport const config = {\n  matcher: [\n    \"/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)\",\n    \"/(api|trpc)(.*)\",\n  ],\n};\n"
  },
  {
    "path": "apps/web/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"strict\": true,\n    \"noEmit\": true,\n    \"esModuleInterop\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"jsx\": \"react-jsx\",\n    \"incremental\": true,\n    \"plugins\": [\n      {\n        \"name\": \"next\"\n      }\n    ],\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    }\n  },\n  \"include\": [\n    \"next-env.d.ts\",\n    \"**/*.ts\",\n    \"**/*.tsx\",\n    \".next/types/**/*.ts\",\n    \".next/dev/types/**/*.ts\"\n  ],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "apps/web/vercel.json",
    "content": "{\n  \"buildCommand\": \"cd ../../packages/backend && npx convex deploy --cmd 'cd ../../apps/web && turbo run build' --cmd-url-env-var-name NEXT_PUBLIC_CONVEX_URL\"\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"convex-monorepo\",\n  \"private\": true,\n  \"scripts\": {\n    \"dev\": \"turbo run dev\",\n    \"build\": \"turbo run build\",\n    \"typecheck\": \"turbo run typecheck\",\n    \"clean\": \"turbo run clean && rm -rf node_modules\",\n    \"format\": \"prettier --write \\\"**/*.{ts,tsx,js,jsx,json,md}\\\" --ignore-path .gitignore\"\n  },\n  \"devDependencies\": {\n    \"prettier\": \"3.8.3\",\n    \"turbo\": \"2.9.6\"\n  },\n  \"engines\": {\n    \"node\": \">=20.20.0\"\n  },\n  \"workspaces\": [\n    \"apps/*\",\n    \"packages/*\"\n  ],\n  \"packageManager\": \"pnpm@10.33.0\"\n}\n"
  },
  {
    "path": "packages/backend/.gitignore",
    "content": ".env.local\n.env\n"
  },
  {
    "path": "packages/backend/convex/README.md",
    "content": "# Welcome to your Convex functions directory!\n\nWrite your Convex functions here. See\nhttps://docs.convex.dev/using/writing-convex-functions for more.\n\nA query function that takes two arguments looks like:\n\n```ts\n// functions.js\nimport { query } from \"./_generated/server\";\nimport { v } from \"convex/values\";\n\nexport const myQueryFunction = query({\n  // Validators for arguments.\n  args: {\n    first: v.number(),\n    second: v.string(),\n  },\n\n  // Function implementation.\n  handler: async (ctx, args) => {\n    // Read the database as many times as you need here.\n    // See https://docs.convex.dev/database/reading-data.\n    const documents = await ctx.db.query(\"tablename\").collect();\n\n    // Arguments passed from the client are properties of the args object.\n    console.log(args.first, args.second);\n\n    // Write arbitrary JavaScript here: filter, aggregate, build derived data,\n    // remove non-public properties, or create new objects.\n    return documents;\n  },\n});\n```\n\nUsing this query function in a React component looks like:\n\n```ts\nconst data = useQuery(api.functions.myQueryFunction, {\n  first: 10,\n  second: \"hello\",\n});\n```\n\nA mutation function looks like:\n\n```ts\n// functions.js\nimport { mutation } from \"./_generated/server\";\nimport { v } from \"convex/values\";\n\nexport const myMutationFunction = mutation({\n  // Validators for arguments.\n  args: {\n    first: v.string(),\n    second: v.string(),\n  },\n\n  // Function implementation.\n  handler: async (ctx, args) => {\n    // Insert or modify documents in the database here.\n    // Mutations can also read from the database like queries.\n    // See https://docs.convex.dev/database/writing-data.\n    const message = { body: args.first, author: args.second };\n    const id = await ctx.db.insert(\"messages\", message);\n\n    // Optionally, return a value from your mutation.\n    return await ctx.db.get(id);\n  },\n});\n```\n\nUsing this mutation function in a React component looks like:\n\n```ts\nconst mutation = useMutation(api.functions.myMutationFunction);\nfunction handleButtonPress() {\n  // fire and forget, the most common way to use mutations\n  mutation({ first: \"Hello!\", second: \"me\" });\n  // OR\n  // use the result once the mutation has completed\n  mutation({ first: \"Hello!\", second: \"me\" }).then((result) =>\n    console.log(result),\n  );\n}\n```\n\nUse the Convex CLI to push your functions to a deployment. See everything\nthe Convex CLI can do by running `npx convex -h` in your project root\ndirectory. To learn more, launch the docs with `npx convex docs`.\n"
  },
  {
    "path": "packages/backend/convex/_generated/api.d.ts",
    "content": "/* eslint-disable */\n/**\n * Generated `api` utility.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport type * as notes from \"../notes.js\";\nimport type * as openai from \"../openai.js\";\nimport type * as utils from \"../utils.js\";\n\nimport type {\n  ApiFromModules,\n  FilterApi,\n  FunctionReference,\n} from \"convex/server\";\n\ndeclare const fullApi: ApiFromModules<{\n  notes: typeof notes;\n  openai: typeof openai;\n  utils: typeof utils;\n}>;\n\n/**\n * A utility for referencing Convex functions in your app's public API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = api.myModule.myFunction;\n * ```\n */\nexport declare const api: FilterApi<\n  typeof fullApi,\n  FunctionReference<any, \"public\">\n>;\n\n/**\n * A utility for referencing Convex functions in your app's internal API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = internal.myModule.myFunction;\n * ```\n */\nexport declare const internal: FilterApi<\n  typeof fullApi,\n  FunctionReference<any, \"internal\">\n>;\n\nexport declare const components: {};\n"
  },
  {
    "path": "packages/backend/convex/_generated/api.js",
    "content": "/* eslint-disable */\n/**\n * Generated `api` utility.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport { anyApi, componentsGeneric } from \"convex/server\";\n\n/**\n * A utility for referencing Convex functions in your app's API.\n *\n * Usage:\n * ```js\n * const myFunctionReference = api.myModule.myFunction;\n * ```\n */\nexport const api = anyApi;\nexport const internal = anyApi;\nexport const components = componentsGeneric();\n"
  },
  {
    "path": "packages/backend/convex/_generated/dataModel.d.ts",
    "content": "/* eslint-disable */\n/**\n * Generated data model types.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport type {\n  DataModelFromSchemaDefinition,\n  DocumentByName,\n  TableNamesInDataModel,\n  SystemTableNames,\n} from \"convex/server\";\nimport type { GenericId } from \"convex/values\";\nimport schema from \"../schema.js\";\n\n/**\n * The names of all of your Convex tables.\n */\nexport type TableNames = TableNamesInDataModel<DataModel>;\n\n/**\n * The type of a document stored in Convex.\n *\n * @typeParam TableName - A string literal type of the table name (like \"users\").\n */\nexport type Doc<TableName extends TableNames> = DocumentByName<\n  DataModel,\n  TableName\n>;\n\n/**\n * An identifier for a document in Convex.\n *\n * Convex documents are uniquely identified by their `Id`, which is accessible\n * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids).\n *\n * Documents can be loaded using `db.get(tableName, id)` in query and mutation functions.\n *\n * IDs are just strings at runtime, but this type can be used to distinguish them from other\n * strings when type checking.\n *\n * @typeParam TableName - A string literal type of the table name (like \"users\").\n */\nexport type Id<TableName extends TableNames | SystemTableNames> =\n  GenericId<TableName>;\n\n/**\n * A type describing your Convex data model.\n *\n * This type includes information about what tables you have, the type of\n * documents stored in those tables, and the indexes defined on them.\n *\n * This type is used to parameterize methods like `queryGeneric` and\n * `mutationGeneric` to make them type-safe.\n */\nexport type DataModel = DataModelFromSchemaDefinition<typeof schema>;\n"
  },
  {
    "path": "packages/backend/convex/_generated/server.d.ts",
    "content": "/* eslint-disable */\n/**\n * Generated utilities for implementing server-side Convex query and mutation functions.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport {\n  ActionBuilder,\n  HttpActionBuilder,\n  MutationBuilder,\n  QueryBuilder,\n  GenericActionCtx,\n  GenericMutationCtx,\n  GenericQueryCtx,\n  GenericDatabaseReader,\n  GenericDatabaseWriter,\n} from \"convex/server\";\nimport type { DataModel } from \"./dataModel.js\";\n\n/**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an `export` to name it and make it accessible.\n */\nexport declare const query: QueryBuilder<DataModel, \"public\">;\n\n/**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an `export` to name it and make it accessible.\n */\nexport declare const internalQuery: QueryBuilder<DataModel, \"internal\">;\n\n/**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.\n */\nexport declare const mutation: MutationBuilder<DataModel, \"public\">;\n\n/**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.\n */\nexport declare const internalMutation: MutationBuilder<DataModel, \"internal\">;\n\n/**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an `export` to name it and make it accessible.\n */\nexport declare const action: ActionBuilder<DataModel, \"public\">;\n\n/**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an `export` to name it and make it accessible.\n */\nexport declare const internalAction: ActionBuilder<DataModel, \"internal\">;\n\n/**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in `convex/http.js`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API `Request` object as its second.\n * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.\n */\nexport declare const httpAction: HttpActionBuilder;\n\n/**\n * A set of services for use within Convex query functions.\n *\n * The query context is passed as the first argument to any Convex query\n * function run on the server.\n *\n * This differs from the {@link MutationCtx} because all of the services are\n * read-only.\n */\nexport type QueryCtx = GenericQueryCtx<DataModel>;\n\n/**\n * A set of services for use within Convex mutation functions.\n *\n * The mutation context is passed as the first argument to any Convex mutation\n * function run on the server.\n */\nexport type MutationCtx = GenericMutationCtx<DataModel>;\n\n/**\n * A set of services for use within Convex action functions.\n *\n * The action context is passed as the first argument to any Convex action\n * function run on the server.\n */\nexport type ActionCtx = GenericActionCtx<DataModel>;\n\n/**\n * An interface to read from the database within Convex query functions.\n *\n * The two entry points are {@link DatabaseReader.get}, which fetches a single\n * document by its {@link Id}, or {@link DatabaseReader.query}, which starts\n * building a query.\n */\nexport type DatabaseReader = GenericDatabaseReader<DataModel>;\n\n/**\n * An interface to read from and write to the database within Convex mutation\n * functions.\n *\n * Convex guarantees that all writes within a single mutation are\n * executed atomically, so you never have to worry about partial writes leaving\n * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control)\n * for the guarantees Convex provides your functions.\n */\nexport type DatabaseWriter = GenericDatabaseWriter<DataModel>;\n"
  },
  {
    "path": "packages/backend/convex/_generated/server.js",
    "content": "/* eslint-disable */\n/**\n * Generated utilities for implementing server-side Convex query and mutation functions.\n *\n * THIS CODE IS AUTOMATICALLY GENERATED.\n *\n * To regenerate, run `npx convex dev`.\n * @module\n */\n\nimport {\n  actionGeneric,\n  httpActionGeneric,\n  queryGeneric,\n  mutationGeneric,\n  internalActionGeneric,\n  internalMutationGeneric,\n  internalQueryGeneric,\n} from \"convex/server\";\n\n/**\n * Define a query in this Convex app's public API.\n *\n * This function will be allowed to read your Convex database and will be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an `export` to name it and make it accessible.\n */\nexport const query = queryGeneric;\n\n/**\n * Define a query that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to read from your Convex database. It will not be accessible from the client.\n *\n * @param func - The query function. It receives a {@link QueryCtx} as its first argument.\n * @returns The wrapped query. Include this as an `export` to name it and make it accessible.\n */\nexport const internalQuery = internalQueryGeneric;\n\n/**\n * Define a mutation in this Convex app's public API.\n *\n * This function will be allowed to modify your Convex database and will be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.\n */\nexport const mutation = mutationGeneric;\n\n/**\n * Define a mutation that is only accessible from other Convex functions (but not from the client).\n *\n * This function will be allowed to modify your Convex database. It will not be accessible from the client.\n *\n * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument.\n * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible.\n */\nexport const internalMutation = internalMutationGeneric;\n\n/**\n * Define an action in this Convex app's public API.\n *\n * An action is a function which can execute any JavaScript code, including non-deterministic\n * code and code with side-effects, like calling third-party services.\n * They can be run in Convex's JavaScript environment or in Node.js using the \"use node\" directive.\n * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}.\n *\n * @param func - The action. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped action. Include this as an `export` to name it and make it accessible.\n */\nexport const action = actionGeneric;\n\n/**\n * Define an action that is only accessible from other Convex functions (but not from the client).\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument.\n * @returns The wrapped function. Include this as an `export` to name it and make it accessible.\n */\nexport const internalAction = internalActionGeneric;\n\n/**\n * Define an HTTP action.\n *\n * The wrapped function will be used to respond to HTTP requests received\n * by a Convex deployment if the requests matches the path and method where\n * this action is routed. Be sure to route your httpAction in `convex/http.js`.\n *\n * @param func - The function. It receives an {@link ActionCtx} as its first argument\n * and a Fetch API `Request` object as its second.\n * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.\n */\nexport const httpAction = httpActionGeneric;\n"
  },
  {
    "path": "packages/backend/convex/auth.config.ts",
    "content": "import { type AuthConfig } from \"convex/server\";\n\nconst clerkJwtIssuerDomain = process.env.CLERK_JWT_ISSUER_DOMAIN;\n\nif (!clerkJwtIssuerDomain)\n  throw new Error(\n    \"Missing CLERK_JWT_ISSUER_DOMAIN in Convex environment variables\",\n  );\n\nexport default {\n  providers: [\n    {\n      domain: clerkJwtIssuerDomain,\n      applicationID: \"convex\",\n    },\n  ],\n} satisfies AuthConfig;\n"
  },
  {
    "path": "packages/backend/convex/notes.ts",
    "content": "import { mutation, query } from \"./_generated/server\";\nimport { v } from \"convex/values\";\nimport { type Auth } from \"convex/server\";\nimport { internal } from \"./_generated/api\";\n\nexport async function getUserId({ auth }: { auth: Auth }) {\n  return (await auth.getUserIdentity())?.subject ?? null;\n}\n\nasync function requireUserId({ auth }: { auth: Auth }) {\n  const userId = await getUserId({ auth });\n  if (userId) return userId;\n\n  throw new Error(\n    \"Authenticated user was required, but no Clerk subject was found\",\n  );\n}\n\n// Get all notes for a specific user\nexport const getNotes = query({\n  args: {},\n  handler: async (ctx) => {\n    const userId = await getUserId(ctx);\n    if (!userId) return [];\n\n    return await ctx.db\n      .query(\"notes\")\n      .withIndex(\"by_userId\", (q) => q.eq(\"userId\", userId))\n      .order(\"desc\")\n      .take(100);\n  },\n});\n\n// Get note for a specific note\nexport const getNote = query({\n  args: {\n    id: v.optional(v.string()),\n  },\n  handler: async (ctx, args) => {\n    const { id } = args;\n    if (!id) return null;\n\n    const normalizedId = ctx.db.normalizeId(\"notes\", id);\n    if (!normalizedId) return null;\n\n    const userId = await getUserId(ctx);\n    if (!userId) return null;\n\n    const note = await ctx.db.get(normalizedId);\n    if (!note || note.userId !== userId) return null;\n\n    return note;\n  },\n});\n\n// Create a new note for a user\nexport const createNote = mutation({\n  args: {\n    title: v.string(),\n    content: v.string(),\n    isSummary: v.boolean(),\n  },\n  handler: async (ctx, { title, content, isSummary }) => {\n    const userId = await requireUserId(ctx);\n    const noteId = await ctx.db.insert(\"notes\", { userId, title, content });\n\n    if (isSummary) {\n      await ctx.scheduler.runAfter(0, internal.openai.summary, {\n        id: noteId,\n        title,\n        content,\n      });\n    }\n\n    return noteId;\n  },\n});\n\nexport const deleteNote = mutation({\n  args: {\n    noteId: v.id(\"notes\"),\n  },\n  handler: async (ctx, { noteId }) => {\n    const userId = await requireUserId(ctx);\n    const note = await ctx.db.get(noteId);\n\n    if (!note) throw new Error(`Note '${noteId}' could not be found`);\n\n    if (note.userId !== userId)\n      throw new Error(`User '${userId}' cannot delete note '${noteId}'`);\n\n    await ctx.db.delete(noteId);\n  },\n});\n"
  },
  {
    "path": "packages/backend/convex/openai.ts",
    "content": "import OpenAI from \"openai\";\nimport { internalAction, internalMutation, query } from \"./_generated/server\";\nimport { v } from \"convex/values\";\nimport { internal } from \"./_generated/api\";\nimport { missingEnvVariableUrl } from \"./utils\";\n\nexport const openaiKeySet = query({\n  args: {},\n  handler: async () => {\n    return Boolean(process.env.OPENAI_API_KEY);\n  },\n});\n\nexport const summary = internalAction({\n  args: {\n    id: v.id(\"notes\"),\n    title: v.string(),\n    content: v.string(),\n  },\n  handler: async (ctx, { id, title, content }) => {\n    const apiKey = process.env.OPENAI_API_KEY;\n    if (!apiKey) {\n      const error = missingEnvVariableUrl(\n        \"OPENAI_API_KEY\",\n        \"https://platform.openai.com/account/api-keys\",\n      );\n      console.error(error);\n      await ctx.runMutation(internal.openai.saveSummary, {\n        id: id,\n        summary: error,\n      });\n      return;\n    }\n\n    const openai = new OpenAI({ apiKey });\n    const output = await openai.responses.create({\n      model: \"gpt-5.4-mini\",\n      instructions:\n        \"You summarize user notes in concise plain English. Respond with summary text only.\",\n      input: `Summarize the following note.\\n\\nTitle: ${title}\\n\\nContent:\\n${content}`,\n    });\n    const summary = output.output_text.trim();\n\n    if (!summary)\n      throw new Error(`OpenAI returned an empty summary for note '${id}'`);\n\n    await ctx.runMutation(internal.openai.saveSummary, {\n      id,\n      summary,\n    });\n  },\n});\n\nexport const saveSummary = internalMutation({\n  args: {\n    id: v.id(\"notes\"),\n    summary: v.string(),\n  },\n  handler: async (ctx, { id, summary }) => {\n    await ctx.db.patch(id, {\n      summary,\n    });\n  },\n});\n"
  },
  {
    "path": "packages/backend/convex/schema.ts",
    "content": "import { defineSchema, defineTable } from \"convex/server\";\nimport { v } from \"convex/values\";\n\nexport default defineSchema({\n  notes: defineTable({\n    userId: v.string(),\n    title: v.string(),\n    content: v.string(),\n    summary: v.optional(v.string()),\n  }).index(\"by_userId\", [\"userId\"]),\n});\n"
  },
  {
    "path": "packages/backend/convex/tsconfig.json",
    "content": "{\n  /* This TypeScript project config describes the environment that\n   * Convex functions run in and is used to typecheck them.\n   * You can modify it, but some settings required to use Convex.\n   */\n  \"compilerOptions\": {\n    /* These settings are not required by Convex and can be modified. */\n    \"allowJs\": true,\n    \"strict\": true,\n\n    /* These compiler options are required by Convex */\n    \"target\": \"ESNext\",\n    \"lib\": [\"ES2021\", \"dom\"],\n    \"forceConsistentCasingInFileNames\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"Bundler\",\n    \"isolatedModules\": true,\n    \"skipLibCheck\": true,\n    \"noEmit\": true\n  },\n  \"include\": [\"./**/*\"],\n  \"exclude\": [\"./_generated\"]\n}\n"
  },
  {
    "path": "packages/backend/convex/utils.ts",
    "content": "export function missingEnvVariableUrl(envVarName: string, whereToGet: string) {\n  const deployment = deploymentName();\n  if (!deployment) return `Missing ${envVarName} in environment variables.`;\n  return (\n    `\\n  Missing ${envVarName} in environment variables.\\n\\n` +\n    `  Get it from ${whereToGet} .\\n  Paste it on the Convex dashboard:\\n` +\n    `  https://dashboard.convex.dev/d/${deployment}/settings?var=${envVarName}`\n  );\n}\n\nexport function deploymentName() {\n  const url = process.env.CONVEX_CLOUD_URL;\n  if (!url) return undefined;\n  const regex = new RegExp(\"https://(.+).convex.cloud\");\n  return regex.exec(url)?.[1];\n}\n"
  },
  {
    "path": "packages/backend/package.json",
    "content": "{\n  \"name\": \"@packages/backend\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"scripts\": {\n    \"dev\": \"convex dev\",\n    \"setup\": \"convex dev --until-success\",\n    \"typecheck\": \"tsc --noEmit -p convex\"\n  },\n  \"author\": \"\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"convex\": \"^1.35.1\",\n    \"openai\": \"^6.34.0\"\n  },\n  \"devDependencies\": {\n    \"typescript\": \"6.0.3\"\n  }\n}\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - \"apps/*\"\n  - \"packages/*\"\nallowBuilds:\n  '@clerk/shared': true\n  browser-tabs-lock: true\n  bufferutil: true\n  core-js: true\n  esbuild: true\n  sharp: true\n  unrs-resolver: true\n  utf-8-validate: true\n\nnodeLinker: hoisted\n"
  },
  {
    "path": "renovate.json",
    "content": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"packageRules\": [\n    {\n      \"matchUpdateTypes\": [\"minor\", \"patch\", \"pin\", \"digest\"],\n      \"automerge\": true\n    },\n    {\n      \"matchDepTypes\": [\"devDependencies\"],\n      \"automerge\": true\n    }\n  ],\n  \"extends\": [\"config:best-practices\"]\n}\n"
  },
  {
    "path": "turbo.json",
    "content": "{\n  \"$schema\": \"https://turbo.build/schema.json\",\n  \"globalDependencies\": [\"**/.env.*local\"],\n  \"ui\": \"tui\",\n  \"tasks\": {\n    \"build\": {\n      \"outputs\": [\"dist/**\", \".next/**\", \"!.next/cache/**\"],\n      \"dependsOn\": [\"^build\"]\n    },\n    \"dev\": {\n      \"cache\": false,\n      \"persistent\": true\n    },\n    \"lint\": {},\n    \"typecheck\": {},\n    \"clean\": {\n      \"cache\": false\n    }\n  }\n}\n"
  }
]