diff --git a/Dockerfile b/Dockerfile
index 2730dccb9..a605e47e1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -24,12 +24,14 @@ ARG PUBLIC_APPWRITE_ENDPOINT
ARG PUBLIC_GROWTH_ENDPOINT
ARG PUBLIC_STRIPE_KEY
ARG SENTRY_AUTH_TOKEN
+ARG PUBLIC_PROJECT_PROFILE
ENV PUBLIC_APPWRITE_ENDPOINT=$PUBLIC_APPWRITE_ENDPOINT
ENV PUBLIC_GROWTH_ENDPOINT=$PUBLIC_GROWTH_ENDPOINT
ENV PUBLIC_CONSOLE_MODE=$PUBLIC_CONSOLE_MODE
ENV PUBLIC_STRIPE_KEY=$PUBLIC_STRIPE_KEY
ENV SENTRY_AUTH_TOKEN=$SENTRY_AUTH_TOKEN
+ENV PUBLIC_PROJECT_PROFILE=$PUBLIC_PROJECT_PROFILE
ENV NODE_OPTIONS=--max_old_space_size=8192
RUN pnpm run build
@@ -38,5 +40,5 @@ FROM nginx:1.25-alpine
EXPOSE 80
-COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
+COPY docker/nginx.$PUBLIC_PROJECT_PROFILE.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build /usr/share/nginx/html/console
\ No newline at end of file
diff --git a/docker/nginx.conf b/docker/nginx.console.conf
similarity index 100%
rename from docker/nginx.conf
rename to docker/nginx.console.conf
diff --git a/docker/nginx.studio.conf b/docker/nginx.studio.conf
new file mode 100644
index 000000000..1110b3b06
--- /dev/null
+++ b/docker/nginx.studio.conf
@@ -0,0 +1,39 @@
+map $sent_http_content_type $expires {
+ # cache everything for 1 year
+ default 1y;
+ # html files shouldn't be cached for single-page applications
+ text/html off;
+}
+
+server {
+ listen 80;
+ server_name localhost;
+
+ # serve compressed file if filename.gz exists
+ gzip_static on;
+
+ location /studio {
+ root /usr/share/nginx/html;
+ index index.html index.htm;
+ try_files $uri /studio/index.html;
+
+ # Add cache headers
+ expires $expires;
+ add_header Pragma public;
+ add_header Cache-Control "public";
+
+ # Deny IE browsers from going into quirks mode
+ add_header X-UA-Compatible "IE=Edge";
+ # X-Frame-Options is to prevent from clickJacking attack
+ add_header X-Frame-Options SAMEORIGIN;
+ # This header enables the Cross-site scripting (XSS) filter
+ add_header X-XSS-Protection "1; mode=block;";
+ # disable content-type sniffing on some browsers.
+ add_header X-Content-Type-Options nosniff;
+ }
+
+ location / {
+ absolute_redirect off;
+ return 301 /studio;
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 227442430..ada91dd38 100644
--- a/package.json
+++ b/package.json
@@ -34,6 +34,7 @@
"cron-parser": "^4.9.0",
"dayjs": "^1.11.13",
"deep-equal": "^2.2.3",
+ "dotenv": "^16.4.7",
"echarts": "^5.6.0",
"envfile": "^7.1.0",
"ignore": "^6.0.2",
@@ -48,6 +49,7 @@
},
"devDependencies": {
"@eslint/compat": "^1.2.7",
+ "@eslint/js": "^9.23.0",
"@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.86.5",
"@playwright/test": "^1.51.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ea9cc1732..fdcf03169 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -47,6 +47,9 @@ importers:
deep-equal:
specifier: ^2.2.3
version: 2.2.3
+ dotenv:
+ specifier: ^16.4.7
+ version: 16.4.7
echarts:
specifier: ^5.6.0
version: 5.6.0
@@ -84,6 +87,9 @@ importers:
'@eslint/compat':
specifier: ^1.2.7
version: 1.2.7(eslint@9.23.0)
+ '@eslint/js':
+ specifier: ^9.23.0
+ version: 9.23.0
'@melt-ui/pp':
specifier: ^0.3.2
version: 0.3.2(@melt-ui/svelte@0.86.5(svelte@5.25.3))(svelte@5.25.3)
diff --git a/src/app.html b/src/app.html
index 18a92b1fa..675d85d59 100644
--- a/src/app.html
+++ b/src/app.html
@@ -5,9 +5,9 @@
-
-
-
+
+
+
%sveltekit.head%
diff --git a/src/hooks.server.ts b/src/hooks.server.ts
index e54c183db..8c17e3e98 100644
--- a/src/hooks.server.ts
+++ b/src/hooks.server.ts
@@ -2,6 +2,7 @@ import { sequence } from '@sveltejs/kit/hooks';
import { handleErrorWithSentry, sentryHandle } from '@sentry/sveltekit';
import * as Sentry from '@sentry/sveltekit';
import { isCloud, isProd } from '$lib/system';
+import type { Handle } from '@sveltejs/kit';
Sentry.init({
enabled: isCloud && isProd,
@@ -9,6 +10,26 @@ Sentry.init({
tracesSampleRate: 1.0
});
-export const handle = sequence(sentryHandle());
+const projectProfile = process.env.PUBLIC_PROJECT_PROFILE || 'console';
+
+const dynamicHtmlTransform: Handle = async ({ event, resolve }) => {
+ let response = await resolve(event);
+
+ if (response.headers.get('content-type')?.includes('text/html')) {
+ let html = await response.text();
+
+ // Replace '/console/' dynamically with the project profile
+ html = html.replace(/\/{project_profile}\//g, `/${projectProfile}/`);
+
+ response = new Response(html, {
+ status: response.status,
+ headers: response.headers
+ });
+ }
+
+ return response;
+};
+
+export const handle = sequence(sentryHandle(), dynamicHtmlTransform);
export const handleError = handleErrorWithSentry();
diff --git a/src/lib/components/breadcrumbs.svelte b/src/lib/components/breadcrumbs.svelte
index 4acd8a6a4..194d0b6e9 100644
--- a/src/lib/components/breadcrumbs.svelte
+++ b/src/lib/components/breadcrumbs.svelte
@@ -9,7 +9,7 @@
} from '@appwrite.io/pink-icons-svelte';
import { BottomSheet } from '$lib/components';
import { isSmallViewport } from '$lib/stores/viewport';
- import { isCloud } from '$lib/system';
+ import { isCloud, isStudio } from '$lib/system';
import { goto } from '$app/navigation';
import { base } from '$app/paths';
import { newOrgModal } from '$lib/stores/organization';
@@ -80,7 +80,7 @@
title: 'Switch Organization',
items: organizations.map((organization) => ({
name: organization.name,
- href: `/console/organization-${organization?.$id}`
+ href: `${base}/organization-${organization?.$id}`
}))
},
bottom: {
@@ -101,7 +101,7 @@
items: [
{
name: 'Organization overview',
- href: `/console/organization-${selectedOrg?.$id}`
+ href: `${base}/organization-${selectedOrg?.$id}`
}
]
},
@@ -139,12 +139,12 @@
if (index < 4) {
return {
name: project.name,
- href: `/console/project-${project.$id}/overview`
+ href: `${base}/project-${project.$id}/overview`
};
} else if (index === 4) {
return {
name: 'All projects',
- href: `/console/organization-${selectedOrg?.$id}`
+ href: `${base}/organization-${selectedOrg?.$id}`
};
}
return null;
@@ -156,7 +156,7 @@
{
name: 'Create project',
trailingIcon: IconPlus,
- href: `/console/organization-${selectedOrg?.$id}?create-project`
+ href: `${base}/organization-${selectedOrg?.$id}?create-project`
}
]
},
@@ -167,7 +167,7 @@
{
name: 'Create project',
trailingIcon: IconPlus,
- href: `/console/organization-${selectedOrg?.$id}?create-project`
+ href: `${base}/organization-${selectedOrg?.$id}?create-project`
}
]
}
@@ -185,7 +185,9 @@
{#if !$isSmallViewport}
-
/
+ {#if !isStudio}
+
/
+ {/if}
@@ -239,7 +241,7 @@
@@ -270,7 +272,7 @@
@@ -315,7 +317,7 @@
{#if index < 4}
@@ -323,7 +325,7 @@
@@ -335,7 +337,7 @@
Create project
diff --git a/src/lib/components/studio/sidebarOrganization.svelte b/src/lib/components/studio/sidebarOrganization.svelte
new file mode 100644
index 000000000..0af4c1ef8
--- /dev/null
+++ b/src/lib/components/studio/sidebarOrganization.svelte
@@ -0,0 +1,37 @@
+
+
+
+
+
diff --git a/src/lib/components/studio/sidebarProject.svelte b/src/lib/components/studio/sidebarProject.svelte
new file mode 100644
index 000000000..64b2166a3
--- /dev/null
+++ b/src/lib/components/studio/sidebarProject.svelte
@@ -0,0 +1,35 @@
+
+
+
+
+
diff --git a/src/lib/layout/container.svelte b/src/lib/layout/container.svelte
index abe25a4a9..a104f9f43 100644
--- a/src/lib/layout/container.svelte
+++ b/src/lib/layout/container.svelte
@@ -1,5 +1,6 @@
-
-
-
-
-
+{#if isStudio}
+
+{:else}
+
-
+{/if}
diff --git a/src/lib/system.ts b/src/lib/system.ts
index 15f745577..8cd3a70f3 100644
--- a/src/lib/system.ts
+++ b/src/lib/system.ts
@@ -6,11 +6,17 @@ export const enum Mode {
SELF_HOSTED = 'self-hosted'
}
+export const enum Profile {
+ CONSOLE = 'console',
+ STUDIO = 'studio'
+}
+
export const VARS = {
CONSOLE_MODE: (env.PUBLIC_CONSOLE_MODE as Mode) ?? undefined,
APPWRITE_ENDPOINT: env.PUBLIC_APPWRITE_ENDPOINT ?? undefined,
GROWTH_ENDPOINT: env.PUBLIC_GROWTH_ENDPOINT ?? undefined,
- PUBLIC_STRIPE_KEY: env.PUBLIC_STRIPE_KEY ?? undefined
+ PUBLIC_STRIPE_KEY: env.PUBLIC_STRIPE_KEY ?? undefined,
+ PROJECT_PROFILE: (env.PUBLIC_PROJECT_PROFILE as Profile) ?? undefined
};
export const ENV = {
@@ -21,7 +27,9 @@ export const ENV = {
};
export const MODE = VARS.CONSOLE_MODE === Mode.CLOUD ? Mode.CLOUD : Mode.SELF_HOSTED;
+export const PROFILE = VARS.PROJECT_PROFILE === Profile.CONSOLE ? Profile.CONSOLE : Profile.STUDIO;
export const isCloud = MODE === Mode.CLOUD;
+export const isStudio = PROFILE === Profile.STUDIO;
export const isSelfHosted = MODE !== Mode.CLOUD;
export const isDev = ENV.DEV;
export const isProd = ENV.PROD;
diff --git a/src/routes/(console)/+layout.svelte b/src/routes/(console)/+layout.svelte
index a3175a8bb..d59b404c9 100644
--- a/src/routes/(console)/+layout.svelte
+++ b/src/routes/(console)/+layout.svelte
@@ -3,6 +3,7 @@
import { BillingPlan, INTERVAL } from '$lib/constants';
import Footer from '$lib/layout/footer.svelte';
import Shell from '$lib/layout/shell.svelte';
+ import ShellStudio from '$lib/layout/shellStudio.svelte';
import { app } from '$lib/stores/app';
import { newOrgModal, organization, type Organization } from '$lib/stores/organization';
import { database, checkForDatabaseBackupPolicies } from '$lib/stores/database';
@@ -32,7 +33,7 @@
import { openMigrationWizard } from './(migration-wizard)';
import { project } from './project-[project]/store';
import { feedback } from '$lib/stores/feedback';
- import { hasStripePublicKey, isCloud, VARS } from '$lib/system';
+ import { hasStripePublicKey, isCloud, isStudio, VARS } from '$lib/system';
import { stripe } from '$lib/stores/stripe';
import MobileSupportModal from './wizard/support/mobileSupportModal.svelte';
import { showSupportModal } from './wizard/support/store';
@@ -329,6 +330,9 @@
+{#if isStudio}
+
+{:else}
+{/if}
{#if $wizard.show && $wizard.component}
diff --git a/src/routes/(console)/organization-[organization]/+page.svelte b/src/routes/(console)/organization-[organization]/+page.svelte
index e17524e2e..22bb61431 100644
--- a/src/routes/(console)/organization-[organization]/+page.svelte
+++ b/src/routes/(console)/organization-[organization]/+page.svelte
@@ -4,7 +4,7 @@
import { Container } from '$lib/layout';
import CreateProject from './createProject.svelte';
import CreateOrganization from '../createOrganization.svelte';
- import { GRACE_PERIOD_OVERRIDE, isCloud } from '$lib/system';
+ import { GRACE_PERIOD_OVERRIDE, isCloud, isStudio } from '$lib/system';
import { page } from '$app/state';
import { registerCommands } from '$lib/commandCenter';
import {
@@ -28,7 +28,7 @@
import { onMount, type ComponentType } from 'svelte';
import { canWriteProjects } from '$lib/stores/roles';
import { checkPricingRefAndRedirect } from '$lib/helpers/pricingRedirect';
- import { Badge, Icon, Typography } from '@appwrite.io/pink-svelte';
+ import { Badge, Divider, Icon, Typography, Card, Layout } from '@appwrite.io/pink-svelte';
import {
IconAndroid,
IconApple,
@@ -48,6 +48,7 @@
let showCreateProjectCloud = false;
function allServiceDisabled(project: Models.Project): boolean {
+ return false;
let disabled = true;
services.load(project);
$services.list.forEach((service) => {
@@ -142,94 +143,124 @@
}
-
-
-
Projects
+{#if isStudio}
+
+
+
+ Projects
+
+
-
- {#if $canWriteProjects}
-
- {/if}
-
- (showCreate = true)}>Empty project
-
-
- Import project Experimental
-
-
-
-
-
+
- {#if data.projects.total}
-
+
+ {#each data.projects.projects as project}
+
+ {/each}
+
+
+
+{:else}
+
+
+
Projects
+
+
+ {#if $canWriteProjects}
+
+ {/if}
+
+ (showCreate = true)}>Empty project
+
+
+ Import project Experimental
+
+
+
+
+
+
+ {#if data.projects.total}
+
+ {#each data.projects.projects as project}
+ {@const platforms = filterPlatforms(
+ project.platforms.map((platform) => getPlatformInfo(platform.type))
+ )}
+
+
+ {project?.platforms?.length ? project?.platforms?.length : 'No'} apps
+
+
+ {project.name}
+
+ {#if allServiceDisabled(project)}
+
+ All services are
+ disabled.
+
+ {/if}
+
+ {#each platforms as platform, i}
+ {#if i < 3}
+ {@const icon = getIconForPlatform(platform.icon)}
+
+
+
+ {/if}
+ {/each}
+ {#if platforms?.length > 3}
+
+ {/if}
+
+ {#if isCloud && regions}
+ {@const region = findRegion(project)}
+
+ {region?.name}
+
+ {/if}
+
+
+ {/each}
+
+ Create a new project
+
+
+ {:else}
+
+ {/if}
+
+
- {#each data.projects.projects as project}
- {@const platforms = filterPlatforms(
- project.platforms.map((platform) => getPlatformInfo(platform.type))
- )}
-
-
- {project?.platforms?.length ? project?.platforms?.length : 'No'} apps
-
-
- {project.name}
-
- {#if allServiceDisabled(project)}
-
- All services are disabled.
-
- {/if}
-
- {#each platforms as platform, i}
- {#if i < 3}
- {@const icon = getIconForPlatform(platform.icon)}
-
-
-
- {/if}
- {/each}
- {#if platforms?.length > 3}
-
- {/if}
-
- {#if isCloud && regions}
- {@const region = findRegion(project)}
-
- {region?.name}
-
- {/if}
-
-
- {/each}
-
- Create a new project
-
-
- {:else}
-
- {/if}
-
-
-
+ total={data.projects.total} />
+
+{/if}
diff --git a/src/routes/(console)/organization-[organization]/+page.ts b/src/routes/(console)/organization-[organization]/+page.ts
index 0282852c2..de073e38c 100644
--- a/src/routes/(console)/organization-[organization]/+page.ts
+++ b/src/routes/(console)/organization-[organization]/+page.ts
@@ -4,6 +4,7 @@ import { getLimit, getPage, pageToOffset } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies } from '$lib/constants';
import type { PageLoad } from './$types';
import { redirect } from '@sveltejs/kit';
+import { base } from '$app/paths';
export const load: PageLoad = async ({ params, url, route, depends, parent }) => {
const { scopes } = await parent();
@@ -12,7 +13,7 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) =>
const limit = getLimit(url, route, CARD_LIMIT);
const offset = pageToOffset(page, limit);
if (!scopes.includes('projects.read') && scopes.includes('billing.read')) {
- return redirect(301, `/console/organization-${params.organization}/billing`);
+ return redirect(301, `${base}/organization-${params.organization}/billing`);
}
return {
diff --git a/src/routes/(console)/organization-[organization]/billing/+page.ts b/src/routes/(console)/organization-[organization]/billing/+page.ts
index 36247292e..2c3c8cef3 100644
--- a/src/routes/(console)/organization-[organization]/billing/+page.ts
+++ b/src/routes/(console)/organization-[organization]/billing/+page.ts
@@ -5,12 +5,13 @@ import { sdk } from '$lib/stores/sdk';
import { redirect } from '@sveltejs/kit';
import type { PageLoad } from './$types';
import { Query } from '@appwrite.io/console';
+import { base } from '$app/paths';
export const load: PageLoad = async ({ parent, depends }) => {
const { organization, scopes } = await parent();
if (!scopes.includes('billing.read')) {
- return redirect(301, `/console/organization-${organization.$id}`);
+ return redirect(301, `${base}/organization-${organization.$id}`);
}
depends(Dependencies.PAYMENT_METHODS);
depends(Dependencies.ORGANIZATION);
diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte
index 615c0800d..34303a5fe 100644
--- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte
+++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/settings/changeOrganization.svelte
@@ -8,6 +8,7 @@
import { addNotification } from '$lib/stores/notifications';
import type { OrganizationList } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
+ import { base } from '$app/paths';
export let domain: Domain;
export let organizations: OrganizationList;
@@ -20,7 +21,7 @@
type: 'success',
message: 'Domain moved successfully'
});
- await goto(`/console/organization-${selectedOrg}/domains/`);
+ await goto(`${base}/organization-${selectedOrg}/domains/`);
await invalidate(Dependencies.ORGANIZATION);
await invalidate(Dependencies.DOMAINS);
} catch (e) {
diff --git a/src/routes/(studio)/+layout.svelte b/src/routes/(studio)/+layout.svelte
new file mode 100644
index 000000000..da755c82b
--- /dev/null
+++ b/src/routes/(studio)/+layout.svelte
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+ {#if hasProjectSidebar}
+
+ {:else}
+
+ {/if}
+
+
+
+
diff --git a/src/routes/(studio)/+layout.ts b/src/routes/(studio)/+layout.ts
new file mode 100644
index 000000000..d51edd31e
--- /dev/null
+++ b/src/routes/(studio)/+layout.ts
@@ -0,0 +1,70 @@
+import { Dependencies } from '$lib/constants';
+import type { Plan } from '$lib/sdk/billing';
+import type { Tier } from '$lib/stores/billing';
+import { sdk } from '$lib/stores/sdk';
+import { isCloud } from '$lib/system';
+import type { LayoutLoad } from './$types';
+import { Query } from '@appwrite.io/console';
+
+export const load: LayoutLoad = async ({ params, fetch, depends, parent }) => {
+ await parent();
+ depends(Dependencies.RUNTIMES);
+ depends(Dependencies.CONSOLE_VARIABLES);
+ depends(Dependencies.ORGANIZATION);
+
+ const prefs = await sdk.forConsole.account.getPrefs();
+
+ const { endpoint, project } = sdk.forConsole.client.config;
+ const versionPromise = fetch(`${endpoint}/health/version`, {
+ headers: {
+ 'X-Appwrite-Project': project
+ }
+ }).then((response) => response.json() as { version?: string });
+
+ const variablesPromise = sdk.forConsole.console.variables();
+
+ const [data, variables] = await Promise.all([versionPromise, variablesPromise]);
+
+ let plansInfo = new Map
();
+ if (isCloud) {
+ const plansArray = await sdk.forConsole.billing.getPlansInfo();
+ plansInfo = plansArray.plans.reduce((map, plan) => {
+ map.set(plan.$id as Tier, plan);
+ return map;
+ }, new Map());
+ }
+
+ const organizations = !isCloud
+ ? await sdk.forConsole.teams.list()
+ : await sdk.forConsole.billing.listOrganization();
+
+ let projects = [];
+ let currentOrgId = params.organization ? params.organization : prefs.organization;
+
+ if (!currentOrgId && organizations.teams.length > 0) {
+ currentOrgId = organizations.teams[0].$id;
+ }
+ if (currentOrgId) {
+ const orgProjects = await sdk.forConsole.projects.list([
+ Query.equal('teamId', currentOrgId),
+ Query.limit(100),
+ Query.orderDesc('$updatedAt')
+ ]);
+ projects = orgProjects.projects.length > 0 ? orgProjects.projects : [];
+ }
+
+ const selectedOrganizationId =
+ params && params.organization ? params.organization : prefs.organization;
+
+ return {
+ consoleVariables: variables,
+ version: data?.version ?? null,
+ plansInfo,
+ roles: [],
+ scopes: [],
+ projects: projects,
+ currentProjectId: params.project ?? '',
+ organizations: organizations,
+ currentOrganization: organizations.teams.find((org) => org.$id === selectedOrganizationId)
+ };
+};
diff --git a/src/routes/(studio)/org-[organization]/+page.svelte b/src/routes/(studio)/org-[organization]/+page.svelte
new file mode 100644
index 000000000..b97b46e7c
--- /dev/null
+++ b/src/routes/(studio)/org-[organization]/+page.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
+ Projects
+ Create project
+
+
+
+
+
+ {#each data.projects as project}
+
+ {/each}
+
+
+
diff --git a/src/routes/(studio)/proj-[project]/+page.svelte b/src/routes/(studio)/proj-[project]/+page.svelte
new file mode 100644
index 000000000..625bf240e
--- /dev/null
+++ b/src/routes/(studio)/proj-[project]/+page.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ Chat
+
+
+ Phasellus a ultricies nulla. Proin tristique aliquam dui. Phasellus porta
+ sodales justo, et feugiat ligula pulvinar sed. Morbi et nulla hendrerit,
+ pellentesque est sodales, euismod magna. Suspendisse vel massa arcu. Nulla
+ ultrices sit amet metus ac euismod. Curabitur ultrices aliquet libero, a
+ pharetra orci tristique in. Etiam egestas fermentum justo ut semper. Sed
+ vulputate eros erat, ac sollicitudin nulla condimentum volutpat. Sed vulputate
+ est ante.
+
+
+
+
+ Iframe
+
+
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 3a1dad550..950455120 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -14,16 +14,23 @@
import { user } from '$lib/stores/user';
import { loading } from '$routes/store';
import { Root } from '@appwrite.io/pink-svelte';
- import { ThemeDark, ThemeLight, ThemeDarkCloud, ThemeLightCloud } from '../themes';
+ import {
+ ThemeDark,
+ ThemeLight,
+ ThemeDarkCloud,
+ ThemeLightCloud,
+ ThemeLightStudio
+ } from '../themes';
import { isSmallViewport, updateViewport } from '$lib/stores/viewport';
import { feedback } from '$lib/stores/feedback';
+ import { isStudio } from '$lib/system.js';
function resolveTheme(theme: AppStore['themeInUse']) {
switch (theme) {
case 'dark':
return isCloud ? ThemeDarkCloud : ThemeDark;
case 'light':
- return isCloud ? ThemeLightCloud : ThemeLight;
+ return isStudio ? ThemeLightStudio : isCloud ? ThemeLightCloud : ThemeLight;
}
}
@@ -149,14 +156,14 @@
{#each preloadFonts as font}
{/each}
-
+
{#if isCloud}
{#each preloadFontsCloud as font}
{/each}
-
+
{/if}
diff --git a/src/routes/+page.ts b/src/routes/+page.ts
index 625a46dec..b7e139a94 100644
--- a/src/routes/+page.ts
+++ b/src/routes/+page.ts
@@ -2,7 +2,7 @@ import { redirect } from '@sveltejs/kit';
import { base } from '$app/paths';
import type { PageLoad } from './$types';
import { sdk } from '$lib/stores/sdk';
-import { VARS } from '$lib/system';
+import { isStudio, VARS } from '$lib/system';
const handleGithubEducationMembership = async (name: string, email: string) => {
const result = await sdk.forConsole.billing.setMembership('github-student-developer');
@@ -39,7 +39,12 @@ export const load: PageLoad = async ({ parent, url }) => {
if (!teamId) {
redirect(303, `${base}/account/organizations${url.search}`);
} else {
- redirect(303, `${base}/organization-${teamId}${url.search}`);
+ redirect(
+ 303,
+ isStudio
+ ? `${base}/org-${teamId}${url.search}`
+ : `${base}/organization-${teamId}${url.search}`
+ );
}
} else {
redirect(303, `${base}/onboarding/create-project${url.search}`);
diff --git a/src/themes/index.ts b/src/themes/index.ts
index 2b2344244..0043a917f 100644
--- a/src/themes/index.ts
+++ b/src/themes/index.ts
@@ -3,3 +3,8 @@ export { default as ThemeLight } from './light.json';
export { default as ThemeDarkCloud } from './dark-cloud.json';
export { default as ThemeLightCloud } from './light-cloud.json';
+
+import { default as StudioLightOverride } from './light-studio.json';
+import { default as ThemeLightBase } from './light.json';
+
+export const ThemeLightStudio = { ...ThemeLightBase, ...StudioLightOverride };
diff --git a/src/themes/light-studio.json b/src/themes/light-studio.json
new file mode 100644
index 000000000..b25007dec
--- /dev/null
+++ b/src/themes/light-studio.json
@@ -0,0 +1,4 @@
+{
+ "bgcolor-accent": "var(--neutral-1000)",
+ "bgcolor-accent-secondary": "var(--neutral-900)"
+}
\ No newline at end of file
diff --git a/svelte.config.js b/svelte.config.js
index 2939a3e1b..0c6a935ef 100644
--- a/svelte.config.js
+++ b/svelte.config.js
@@ -1,6 +1,9 @@
import adapter from '@sveltejs/adapter-static';
import { sveltePreprocess } from 'svelte-preprocess';
import { preprocessMeltUI, sequence } from '@melt-ui/pp';
+import 'dotenv/config';
+
+const projectProfile = process.env.PUBLIC_PROJECT_PROFILE || 'console';
/** @type {import('@sveltejs/kit').Config} */
const config = {
@@ -26,7 +29,7 @@ const config = {
precompress: true
}),
paths: {
- base: '/console'
+ base: `/${projectProfile}`
}
},
vitePlugin: {
diff --git a/vite.config.ts b/vite.config.ts
index d0a9f9bf0..47086a375 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -12,7 +12,7 @@ export default defineConfig({
project: 'console'
}
}),
- sveltekit()
+ sveltekit(),
],
optimizeDeps: {
include: ['echarts', 'prismjs']