Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e3577df
feat: extend `WebsiteGenerator` class for `StudioApp` doctype
ruchamahabal Mar 3, 2025
10c9a3e
feat: eliminate `/studio-app` prefix using generator template as app …
ruchamahabal Mar 4, 2025
cb3fab8
fix: setup frappe-ui resource in renderer
ruchamahabal Mar 5, 2025
b1607c7
fix: enable track changes on app & page + fix doctype list views
ruchamahabal Mar 5, 2025
43310e0
feat: setup StudioAppRenderer as a custom page renderer for all app r…
ruchamahabal Mar 5, 2025
5f0750a
refactor: skip api call, pass app pages & routes in context
ruchamahabal Mar 6, 2025
653d19e
chore: remove unused function
ruchamahabal Mar 6, 2025
aeb3c2d
fix: fetching page blocks based on app name & page route
ruchamahabal Mar 6, 2025
4ec8b28
fix: import missing css in renderer
ruchamahabal Mar 6, 2025
c5eeaca
feat: move app renderer to vue project folder & copy it to generators…
ruchamahabal Mar 6, 2025
7f495bc
chore: add auto-generated renderer file to .gitignore
ruchamahabal Mar 6, 2025
4f09b69
chore: delete auto-generated renderer file
ruchamahabal Mar 6, 2025
a7abd74
fix: set home route to / in studio router
ruchamahabal Mar 6, 2025
89be10c
Merge branch 'develop' into rendering-2
ruchamahabal Mar 7, 2025
0ae9331
fix: add __init__.py to empty generators directory for git to track it
ruchamahabal Mar 7, 2025
bef9910
chore: temporary workaround for HMR in renderer during development
ruchamahabal Mar 7, 2025
043078d
fix: vue router - dynamic route evaluation fails
ruchamahabal Mar 7, 2025
0371722
fix: remove /studio-app prefix from the app creation flow
ruchamahabal Mar 7, 2025
3119b44
fix: duplicate page insertion on new app creation
ruchamahabal Mar 9, 2025
f26ef3b
fix: remove /studio-app prefix from page routing utils
ruchamahabal Mar 9, 2025
cf6a705
fix: opening page links from the app builder
ruchamahabal Mar 9, 2025
8464e76
fix: extra trailing slash in route
ruchamahabal Mar 12, 2025
6534df8
chore: remove studio-app routing from backend
ruchamahabal Mar 14, 2025
895e5c7
fix: favicon in renderer
ruchamahabal Mar 14, 2025
7aa1aa9
fix(renderer): app script linking in dev & prod mode
ruchamahabal Mar 14, 2025
53206ae
chore: remove redundant fonts from assets
ruchamahabal Mar 14, 2025
7129c94
fix: use inter.css from frappe-ui
ruchamahabal Mar 14, 2025
913474d
fix: set `server.origin` in vite config to serve assets to renderer
ruchamahabal Mar 14, 2025
eb89e79
refactor: move renderer.html back to templates and use renderer.ts as…
ruchamahabal Mar 14, 2025
16495f1
fix(UX): always add leading / to page route as required by the vue ro…
ruchamahabal Mar 15, 2025
a0d8e32
revert "refactor: move renderer.html back to templates and use render…
ruchamahabal Mar 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ node_modules
__pycache__
studio/docs/current
studio/public/frontend
studio/www/studio.html
studio/www/studio.html
studio/templates/generators/renderer.html
7 changes: 4 additions & 3 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
<body>
<!-- For the main app builder -->
<div id="studio"></div>
<!-- For rendering apps built by studio -->
<div id="app"></div>
<div id="modals"></div>
<div id="popovers"></div>

<script> window.csrf_token = '{{ csrf_token }}'; </script>
<script>
window.csrf_token = '{{ csrf_token }}';
window.site_url = '{{ site_url }}';
</script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build --base=/assets/studio/frontend/ && yarn copy-html-entry",
"build": "vite build --base=/assets/studio/frontend/ && yarn copy-html-entry && yarn copy-app-renderer",
"copy-html-entry": "cp ../studio/public/frontend/index.html ../studio/www/studio.html",
"copy-app-renderer": "cp ../studio/public/frontend/renderer.html ../studio/templates/generators/renderer.html",
"serve": "vite preview",
"extract-frappeui-types": "tsx src/scripts/tsToJSONGenerator.ts frappeui",
"extract-studio-types": "tsx src/scripts/tsToJSONGenerator.ts studio"
Expand Down
29 changes: 29 additions & 0 deletions frontend/renderer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<!-- Built with Frappe Studio -->
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ app_title }}</title>
</head>
<body>
<div id="app"></div>
<div id="modals"></div>
<div id="popovers"></div>
<script>
window.csrf_token = "{{ csrf_token }}";
window.app_name = "{{ app_name }}";
window.app_route = "{{ app_route }}";
window.app_title = "{{ app_title }}";
window.app_pages = {{ app_pages|tojson }};
</script>
{% if is_developer_mode %}
<!-- workaround for HMR in renderer during development -->
<script type="module" src="http://{{ site_name }}:8080/@vite/client"></script>
<script type="module" src="http://{{ site_name }}:8080/src/renderer.ts"></script>
{% else %}
<script type="module" src="/src/renderer.ts"></script>
{% endif %}
</body>
</html>
Binary file removed frontend/src/assets/Inter/Inter-Black.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Black.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-BlackItalic.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-BlackItalic.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Bold.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Bold.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-BoldItalic.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-BoldItalic.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-ExtraBold.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-ExtraBold.woff2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-ExtraLight.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-ExtraLight.woff2
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Italic.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Italic.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Light.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Light.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-LightItalic.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-LightItalic.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Medium.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Medium.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-MediumItalic.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-MediumItalic.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Regular.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Regular.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-SemiBold.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-SemiBold.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-SemiBoldItalic.woff
Binary file not shown.
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Thin.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-Thin.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-ThinItalic.woff
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-ThinItalic.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-italic.var.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter-roman.var.woff2
Binary file not shown.
Binary file removed frontend/src/assets/Inter/Inter.var.woff2
Binary file not shown.
152 changes: 0 additions & 152 deletions frontend/src/assets/Inter/inter.css

This file was deleted.

17 changes: 11 additions & 6 deletions frontend/src/components/PageOptions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
type="text"
variant="outline"
class="w-full"
@input="(val: string) => (page.route = val)"
:modelValue="pageRoute"
:hideClearButton="true"
@update:modelValue="(val: string) => store.updateActivePage('route', `${app?.route}/${val}`)"
@update:modelValue="
(val: string) => {
store.updateActivePage('route', val.startsWith('/') ? val : `/${val}`)
}
"
/>

<!-- App Route Prefix -->
Expand Down Expand Up @@ -53,10 +56,11 @@ const props = defineProps<{
}>()

const inputRef = ref<InstanceType<typeof Input> | null>(null)

const pageRoute = computed(() => {
return props.page.route.replace(`${props.app?.route}/`, "")
})
const pageRoute = ref(props.page.route)
const setPageRoute = () => {
// remove leading slash from route because app route prefix will be <app.route>/ so that user doesn't have to type the leading slash
pageRoute.value = props.page.route.replace(/^\//, "")
}

const dynamicPadding = computed(() => {
const prefixWidth = props.app?.route?.length * 8 + 15 // Assuming 8px per character plus 4px for padding
Expand All @@ -78,6 +82,7 @@ watch(
// apply dynamic padding to input element when the popover is opened
// to avoid overlapping with the prefix content
applyDynamicPadding()
setPageRoute()
},
{ immediate: true },
)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/StudioToolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
name="external-link"
v-if="store.activePage && store.activePage.published"
class="h-[14px] w-[14px] !text-gray-700 dark:!text-gray-200"
@click="store.openPageInBrowser(store.activePage)"
@click="store.openPageInBrowser(store.activeApp, store.activePage)"
>
</FeatherIcon>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/index.css
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
@import './assets/Inter/inter.css';
@import 'frappe-ui/src/fonts/Inter/inter.css';
@import 'frappe-ui/src/style.css';
31 changes: 21 additions & 10 deletions frontend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import "./index.css"

import { createApp } from "vue"
import { createPinia } from "pinia"
import studio_router from "@/router/studio_router"
import "./setupFrappeUIResource"
import app_router from "@/router/app_router"
import studio_router from "@/router/studio_router"
import App from "./App.vue"

import { resourcesPlugin, FeatherIcon } from "frappe-ui"
import { resourcesPlugin, frappeRequest } from "frappe-ui"
import { registerGlobalComponents } from "./globals"

const studio = createApp(App)
Expand All @@ -18,11 +17,23 @@ studio.use(studio_router)
studio.use(resourcesPlugin)
studio.use(pinia)
registerGlobalComponents(studio)
studio.mount("#studio")

// For rendering apps built by studio
const app = createApp(App)
app.use(app_router)
app.use(pinia)
registerGlobalComponents(app)
app.mount("#app")
declare global {
interface Window {
site_url: string
[key: string]: string
}
}

studio_router.isReady().then(async () => {
if (import.meta.env.DEV) {
await frappeRequest({
url: "/api/method/studio.www.studio.get_context_for_dev",
}).then(async (values: Record<string, any>) => {
for (let key in values) {
window[key] = values[key]
}
})
}
studio.mount("#studio")
})
7 changes: 3 additions & 4 deletions frontend/src/pages/AppContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,18 @@ const rootBlock = ref<Block | null>(null)
watch(
() => route.path,
async () => {
let { appRoute, pageRoute } = route.params as { appRoute: string; pageRoute: string[] }
let { pageRoute } = route.params as { pageRoute: string[] }
const isDynamic = route.meta?.isDynamic
if (appRoute === "studio") return

let currentPath = ""
let currentPath = "/"
if (isDynamic) {
currentPath = route.matched?.[0]?.path
} else if (pageRoute) {
currentPath = pageRoute[0]
}

if (currentPath) {
page.value = await findPageWithRoute(appRoute, currentPath)
page.value = await findPageWithRoute(window.app_name, currentPath)
if (!page.value) return
const blocks = jsonToJs(page.value?.blocks)
if (blocks) {
Expand Down
27 changes: 3 additions & 24 deletions frontend/src/pages/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,8 @@
>
<template #body-content>
<div class="flex flex-col gap-3">
<Input label="App Title" type="text" variant="outline" v-model="newApp.app_title" />

<div class="flex w-full flex-col gap-1">
<label class="block text-xs text-gray-600">App Route</label>
<div class="relative flex items-stretch">
<Input
type="text"
variant="outline"
class="w-full [&>div>input]:pl-[100px]"
:hideClearButton="true"
v-model="newApp.route"
/>

<!-- App Route Prefix -->
<div
class="absolute bottom-[1px] left-[1px] flex items-center rounded-l-[0.4rem] bg-gray-100 text-gray-700"
>
<span class="flex h-[1.65rem] items-center text-nowrap px-2 py-0 text-base">
studio-app/
</span>
</div>
</div>
</div>
<FormControl label="App Title" type="text" variant="outline" v-model="newApp.app_title" />
<FormControl label="App Route" type="text" variant="outline" v-model="newApp.route" />
</div>
</template>
</Dialog>
Expand Down Expand Up @@ -95,7 +74,7 @@ const createStudioApp = (app: NewStudioApp) => {
studioApps.insert
.submit({
app_title: app.app_title,
route: `studio-app/${app.route}`,
route: app.route,
})
.then((res: StudioApp) => {
showDialog.value = false
Expand Down
Loading