diff --git a/package.json b/package.json index 8d1a0d1ba..557835f92 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "@ai-sdk/svelte": "^1.1.24", "@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43", "@faker-js/faker": "^9.9.0", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 463bb83f3..6c7ed1e60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,14 +18,14 @@ importers: specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43 + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43(svelte@5.25.3) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 @@ -269,8 +269,8 @@ packages: peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc} + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43} version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -284,8 +284,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4} + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -3709,7 +3709,7 @@ snapshots: dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3722,7 +3722,7 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43(svelte@5.25.3)': dependencies: '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 diff --git a/src/routes/(console)/project-[region]-[project]/overview/components/CursorIconLarge.svelte b/src/routes/(console)/project-[region]-[project]/overview/components/CursorIconLarge.svelte new file mode 100644 index 000000000..d4619ac20 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/overview/components/CursorIconLarge.svelte @@ -0,0 +1,7 @@ + + + diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/createAndroid.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/createAndroid.svelte index 7add3d070..966047db4 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/createAndroid.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/createAndroid.svelte @@ -37,6 +37,30 @@ const projectId = page.params.project; + const alreadyExistsInstructions = ` + Install the Appwrite Android SDK by adding the following dependency to app-level build.gradle.kts file under dependencies block: + + \`\`\` + implementation("io.appwrite:sdk-for-android:8.1.0") + \`\`\` + + From a suitable lib directory, export the Appwrite client as a global variable: + + \`\`\` + val client = Client() + .setEndpoint("https://fra.cloud.appwrite.io/v1") + .setProject("ai-test-atharva") + + val account = Account(client) + \`\`\` + + On the homepage of the app, create a button that says "Send a ping" and when clicked, it should call the following function: + + \`\`\` + client.ping() + \`\`\` + `; + const gitCloneCode = '\ngit clone https://github.com/appwrite/starter-for-android\ncd starter-for-android\n'; @@ -173,7 +197,11 @@ const val APPWRITE_PUBLIC_ENDPOINT = "${sdk.forProject(page.params.region, page. {#if isPlatformCreated}
- + 1. If you're starting a new project, you can clone our starter kit from diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/createApple.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/createApple.svelte index 9f2cbf1a7..43e32019d 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/createApple.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/createApple.svelte @@ -39,6 +39,30 @@ const projectId = page.params.project; + const alreadyExistsInstructions = ` + Install the Appwrite iOS SDK using the following package URL: + + \`\`\` + https://github.com/appwrite/sdk-for-apple + \`\`\` + + From a suitable lib directory, export the Appwrite client as a global variable: + + \`\`\` + let client = Client() + .setEndpoint("https://fra.cloud.appwrite.io/v1") + .setProject("ai-test-atharva") + + let account = Account(client) + \`\`\` + + On the homepage of the app, create a button that says "Send a ping" and when clicked, it should call the following function: + + \`\`\` + appwrite.ping() + \`\`\` + `; + const gitCloneCode = '\ngit clone https://github.com/appwrite/starter-for-ios\ncd starter-for-ios\n'; @@ -46,7 +70,7 @@ APPWRITE_PROJECT_NAME: "${$project.name}" APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}"`; - let platforms: { [key: string]: PlatformType } = { + const platforms: { [key: string]: PlatformType } = { iOS: PlatformType.Appleios, macOS: PlatformType.Applemacos, watchOS: PlatformType.Applewatchos, @@ -201,7 +225,11 @@ APPWRITE_PUBLIC_ENDPOINT: "${sdk.forProject(page.params.region, page.params.proj {#if isPlatformCreated}
- + 1. If you're starting a new project, you can clone our starter kit from diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte index 0117e5f04..c06185847 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/createFlutter.svelte @@ -39,6 +39,28 @@ const projectId = page.params.project; + const alreadyExistsInstructions = ` + Install the Appwrite Flutter SDK using the following command: + + \`\`\` + flutter pub add appwrite:17.0.0 + \`\`\` + + From a suitable lib directory, export the Appwrite client as a global variable, hardcode the project details too: + + \`\`\` + final Client client = Client() + .setProject("${projectId}") + .setEndpoint("${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}"); + \`\`\` + + On the homepage of the app, create a button that says "Send a ping" and when clicked, it should call the following function: + + \`\`\` + client.ping(); + \`\`\` + `; + const gitCloneCode = '\ngit clone https://github.com/appwrite/starter-for-flutter\ncd starter-for-flutter\n'; @@ -283,7 +305,11 @@ {#if isPlatformCreated}
- + 1. If you're starting a new project, you can clone our starter kit from GitHub using the terminal, VSCode or Android Studio. diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/createReactNative.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/createReactNative.svelte index bc1d56184..d76c674f3 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/createReactNative.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/createReactNative.svelte @@ -39,6 +39,28 @@ const projectId = page.params.project; + const alreadyExistsInstructions = ` + Install the Appwrite React Native SDK using the following command, respect user's package manager of choice and use the one being used in the codebase: + + \`\`\` + npx expo install react-native-appwrite react-native-url-polyfill + \`\`\` + + From a suitable lib directory, export the Appwrite client as a global variable, hardcode the project details too: + + \`\`\` + const client = new Client() + .setProject("${projectId}") + .setEndpoint("${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}"); + \`\`\` + + On the homepage of the app, create a button that says "Send a ping" and when clicked, it should call the following function: + + \`\`\` + client.ping(); + \`\`\` + `; + const gitCloneCode = '\ngit clone https://github.com/appwrite/starter-for-react-native\ncd starter-for-react-native\n'; @@ -46,6 +68,12 @@ EXPO_PUBLIC_APPWRITE_PROJECT_NAME="${$project.name}" EXPO_PUBLIC_APPWRITE_ENDPOINT=${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}`; + const promptConfigCode = ` + const client = new Client() + .setProject("${projectId}") + .setEndpoint("${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}") + `; + let platforms: { [key: string]: PlatformType } = { Android: PlatformType.Reactnativeandroid, iOS: PlatformType.Reactnativeios @@ -227,7 +255,11 @@ EXPO_PUBLIC_APPWRITE_ENDPOINT=${sdk.forProject(page.params.region, page.params.p {#if isPlatformCreated}
- + 1. If you're starting a new project, you can clone our starter kit from diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/createWeb.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/createWeb.svelte index 2521326fc..6b259468e 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/createWeb.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/createWeb.svelte @@ -164,18 +164,50 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p ); const llmConfig: LLMPromptConfig = $derived({ + alreadyExistsInstructions: ` + Install the Appwrite web SDK using the following command. Respect the user's package manager of choice. Do not use NPM if the user uses Bun for example. + + \`\`\`bash + npm install appwrite + \`\`\` + + Create a new \`appwrite.js\` (or equivalent, respecting the framework and language, don't create a JS file if TS is being used in the project) file in a suitable lib directory and have the following code: + + \`\`\`js + import { Client, Account, Databases } from "appwrite"; + + const client = new Client() + .setEndpoint("${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}") + .setProject("${projectId}"); + + const account = new Account(client); + const databases = new Databases(client); + + export { client, account, databases }; + \`\`\` + + On the homepage of the app, create a button that says "Send a ping" and when clicked, it should call the following function: + + \`\`\`js + client.ping(); + \`\`\` + `, title: `Copy prompt: starter kit for Appwrite in ${selectedFramework?.label || 'Web'}`, cloneCommand: `git clone https://github.com/appwrite/starter-for-${selectedFramework?.key}\ncd starter-for-${selectedFramework?.key}`, configFile: selectedFramework?.key === 'angular' ? 'src/environments/environment.ts' - : '.env.example', + : 'appwrite.js', configCode: selectedFramework?.key === 'angular' ? `APPWRITE_PROJECT_ID=${projectId}\nAPPWRITE_PROJECT_NAME=${$project.name}\nAPPWRITE_ENDPOINT=${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}` - : selectedFramework?.updateConfigCode || '', + : ` + const client = new Client() + .setEndpoint("${sdk.forProject(page.params.region, page.params.project).client.config.endpoint}") + .setProject("${projectId}"); + `, configLanguage: selectedFramework?.key === 'angular' ? 'ts' : 'dotenv', - runInstructions: `${selectedFramework?.key === 'angular' ? 'Replace the file with the configuration above' : 'Copy the file `.env.example` to `.env` and update the configuration settings'}. Install project dependencies using \`npm install\`, then run the app using \`${selectedFramework?.runCommand}\`. Demo app runs on http://localhost:${selectedFramework?.portNumber}. Click the \`Send a ping\` button to verify the setup.`, + runInstructions: `${selectedFramework?.key === 'angular' && 'Replace the file with the configuration above'}. Install project dependencies using \`npm install\`, then run the app using \`${selectedFramework?.runCommand}\`. Demo app runs on http://localhost:${selectedFramework?.portNumber}. Click the \`Send a ping\` button to verify the setup.`, using: 'the terminal or VSCode' }); @@ -321,7 +353,7 @@ ${prefix}APPWRITE_ENDPOINT = "${sdk.forProject(page.params.region, page.params.p {#if isPlatformCreated && !isChangingFramework}
- + 1. If you're starting a new project, you can clone our starter kit from diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte index 2f1096cbc..6c5bdeb06 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/llmBanner.svelte @@ -2,29 +2,82 @@ import { copy } from '$lib/helpers/copy'; import { Button } from '$lib/elements/forms'; import { ActionMenu, Alert, Icon, Layout, Popover, Typography } from '@appwrite.io/pink-svelte'; - import { IconChevronDown } from '@appwrite.io/pink-icons-svelte'; + import { IconChevronDown, IconChevronUp, IconLovable } from '@appwrite.io/pink-icons-svelte'; import { addNotification } from '$lib/stores/notifications'; import { buildPlatformConfig, generatePromptFromConfig, type LLMPromptConfig } from './store'; import { Click, trackEvent } from '$lib/actions/analytics'; + import IconAINotification from '../../databases/database-[database]/(suggestions)/icon/aiNotification.svelte'; + import Avatar from '$lib/components/avatar.svelte'; + import CursorIcon from '../components/CursorIconLarge.svelte'; + import type { ComponentType } from 'svelte'; let { platform, configCode, - config: customConfig + alreadyExistsInstructions, + config: customConfig, + openers = [] as Array }: { platform?: string; configCode?: string; + alreadyExistsInstructions?: string; config?: LLMPromptConfig; + openers?: Array; } = $props(); const config = $derived.by(() => { if (customConfig) return customConfig; - if (platform && configCode) return buildPlatformConfig(platform, configCode); + if (platform && configCode) + return buildPlatformConfig(platform, configCode, alreadyExistsInstructions); throw new Error('LlmBanner: must provide either config OR (platform + configCode)'); }); const prompt = $derived(generatePromptFromConfig(config)); + let showAlert = $state(true); + + type OpenerConfig = { + id: SupportedAgents; + label: string; + description: string; + href: (prompt: string) => string; + icon?: ComponentType; + imgSrc?: string; + alt: string; + }; + + type SupportedAgents = 'cursor' | 'lovable'; + + const openersConfig: Record = { + cursor: { + id: 'cursor', + label: 'Open in Cursor', + description: 'Set up starter kit in Cursor', + href: (p: string) => { + const u = new URL('https://cursor.com/link/prompt'); + u.searchParams.set('text', p); + return u.toString(); + }, + icon: CursorIcon, + alt: 'Cursor' + }, + lovable: { + id: 'lovable', + label: 'Open in Lovable', + description: 'Set up starter kit in Lovable', + href: (p: string) => { + const u = new URL('https://lovable.dev/'); + u.searchParams.set('autosubmit', 'true'); + u.searchParams.set('prompt', p); + return u.toString(); + }, + icon: IconLovable, + alt: 'Lovable' + } + }; + + const validOpeners = $derived(openers.filter((id) => openersConfig[id])); + async function copyPrompt() { await copy(prompt); @@ -39,64 +92,94 @@ } - - - - Copy the prompt or open it directly in your preferred tools to get step-by-step - instructions, starter code, and SDK commands for your project. - +{#if showAlert} +
+ (showAlert = false)}> + + + + + + + Copy the prompt or open it directly in an AI tool like Cursor or Lovable to + get step-by-step instructions, starter code, and SDK commands for your + project. + + - - - - + + + {#if validOpeners.length} + + - - - - - - Open in Cursor - - Set up starter kit in Cursor - - - - - - - - - Open in Lovable - - Set up starter kit in Lovable - - - - - - - - - + + + {#each validOpeners as openerId} + {@const o = openersConfig[openerId]} + {#if o} + { + window.open( + o.href(prompt), + '_blank', + 'noopener,noreferrer' + ); + toggle(e); + }}> + + + {#if o.icon} + + {:else if o.imgSrc} + {o.alt} + {/if} + + + {o.label} + + {o.description} + + + + + {/if} + {/each} + + + + {/if} + + + +
+{/if} diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts b/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts index 11a2fa5c7..ea5296d4f 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/store.ts @@ -19,6 +19,7 @@ export type FrameworkType = { export type LLMPromptConfig = { title: string; + alreadyExistsInstructions: string; cloneCommand: string; configFile: string; configCode: string; @@ -32,15 +33,23 @@ export function getCorrectTitle(isConnectPlatform: boolean, platform: string) { } export function generatePromptFromConfig(config: LLMPromptConfig): string { - return `1. If you're starting a new project, you can clone our starter kit from GitHub using ${config.using || 'the terminal'}. + return ` +Follow the steps depending on if a project already exists on user's working directory or not: + +## If a project already exists: +${config.alreadyExistsInstructions} + +## If a project does not exist: + +1. If you're starting a new project, you can clone our starter kit from GitHub using ${config.using || 'the terminal'}. Make sure to clone in the current working directory root so that the files are directly available in the working directory. \`\`\`bash ${config.cloneCommand} \`\`\` -2. Open the file \`${config.configFile}\` and update the configuration settings. +2. Open the file \`${config.configFile}\`, find the code block, replace and hardcode the project details as mentioned below. -\`\`\`${config.configLanguage} +\`\`\` ${config.configCode} \`\`\` @@ -92,15 +101,19 @@ const platformConfigs: Record = { name: 'React Native', title: 'Copy prompt: starter kit for Appwrite in React Native', repoName: 'starter-for-react-native', - configFile: '.env.example', - configLanguage: 'dotenv', + configFile: 'index.ts', + configLanguage: 'typescript', runInstructions: - 'Add your Appwrite credentials to `.env.example` then rename it to `.env` if needed. Run the app on a connected device or simulator using `npm install` followed by `npm run ios` or `npm run android`, then click the `Send a ping` button to verify the setup.', + 'After replacing and hardcoding project details, run the app on a connected device or simulator using `npm install` followed by `npm run ios` or `npm run android`, then click the `Send a ping` button to verify the setup.', using: 'the terminal or VSCode' } }; -export function buildPlatformConfig(platformKey: string, configCode: string): LLMPromptConfig { +export function buildPlatformConfig( + platformKey: string, + configCode: string, + alreadyExistsInstructions: string +): LLMPromptConfig { const config = platformConfigs[platformKey]; if (!config) { throw new Error(`Unknown platform: ${platformKey}`); @@ -108,6 +121,7 @@ export function buildPlatformConfig(platformKey: string, configCode: string): LL return { title: config.title, + alreadyExistsInstructions: alreadyExistsInstructions, cloneCommand: `git clone https://github.com/appwrite/${config.repoName}\ncd ${config.repoName}`, configFile: config.configFile, configCode: configCode,