feat: setup frappe ui
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# Frappe UI Starter
|
||||
|
||||
This template should help get you started developing custom frontend for Frappe
|
||||
apps with Vue 3 and the Frappe UI package.
|
||||
|
||||
This boilerplate sets up Vue 3, Vue Router, TailwindCSS, and Frappe UI out of
|
||||
the box.
|
||||
|
||||
## Usage
|
||||
|
||||
This template is meant to be cloned inside an existing Frappe App. Assuming your
|
||||
apps name is `todo`. Clone this template in the root folder of your app using `degit`.
|
||||
|
||||
```
|
||||
cd apps/todo
|
||||
npx degit netchampfaris/frappe-ui-starter frontend
|
||||
cd frontend
|
||||
yarn
|
||||
yarn dev
|
||||
```
|
||||
|
||||
In a development environment, you need to put the below key-value pair in your `site_config.json` file:
|
||||
|
||||
```
|
||||
"ignore_csrf": 1
|
||||
```
|
||||
|
||||
This will prevent `CSRFToken` errors while using the vite dev server. In production environment, the `csrf_token` is attached to the `window` object in `index.html` for you.
|
||||
|
||||
The Vite dev server will start on the port `8080`. This can be changed from `vite.config.js`.
|
||||
The development server is configured to proxy your frappe app (usually running on port `8000`). If you have a site named `todo.test`, open `http://todo.test:8080` in your browser. If you see a button named "Click to send 'ping' request", congratulations!
|
||||
|
||||
If you notice the browser URL is `/frontend`, this is the base URL where your frontend app will run in production.
|
||||
To change this, open `src/router.js` and change the base URL passed to `createWebHistory`.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Vue 3](https://v3.vuejs.org/guide/introduction.html)
|
||||
- [Vue Router](https://next.router.vuejs.org/guide/)
|
||||
- [Frappe UI](https://github.com/frappe/frappe-ui)
|
||||
- [TailwindCSS](https://tailwindcss.com/docs/utility-first)
|
||||
- [Vite](https://vitejs.dev/guide/)
|
||||
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<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>Frappe UI App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="modals"></div>
|
||||
<div id="popovers"></div>
|
||||
|
||||
<script> window.csrf_token = '{{ csrf_token }}'; </script>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "frappe-ui-frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"feather-icons": "^4.28.0",
|
||||
"frappe-ui": "^0.0.105",
|
||||
"vue": "^3.2.25",
|
||||
"vue-router": "^4.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^2.0.0",
|
||||
"autoprefixer": "^10.4.2",
|
||||
"postcss": "^8.4.5",
|
||||
"tailwindcss": "^3.0.15",
|
||||
"vite": "^2.7.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 440 B |
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,152 @@
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-Thin.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Thin.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-ThinItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ThinItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLight.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraLight.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLightItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraLightItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-Light.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Light.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-LightItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-LightItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Regular.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Regular.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Italic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Italic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-Medium.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Medium.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-MediumItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-MediumItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBold.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-SemiBold.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBoldItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-SemiBoldItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-Bold.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Bold.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-BoldItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-BoldItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBold.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraBold.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBoldItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraBoldItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-Black.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Black.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-BlackItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-BlackItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
@import './assets/Inter/inter.css';
|
||||
@import 'frappe-ui/src/style.css';
|
||||
@@ -0,0 +1,17 @@
|
||||
import './index.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import router from './router'
|
||||
import App from './App.vue'
|
||||
|
||||
import { Button, setConfig, frappeRequest, resourcesPlugin } from 'frappe-ui'
|
||||
|
||||
let app = createApp(App)
|
||||
|
||||
setConfig('resourceFetcher', frappeRequest)
|
||||
|
||||
app.use(router)
|
||||
app.use(resourcesPlugin)
|
||||
|
||||
app.component('Button', Button)
|
||||
app.mount('#app')
|
||||
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<div class="text-xl font-semibold">
|
||||
All Courses
|
||||
</div>
|
||||
<div>
|
||||
{{ courses }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Courses",
|
||||
resources: {
|
||||
courses() {
|
||||
return {
|
||||
type: "list",
|
||||
doctype: "LMS Course",
|
||||
fields: ["name", "title", "short_introduction", "image"],
|
||||
orderBy: "creation desc",
|
||||
filters: {
|
||||
published: 1
|
||||
},
|
||||
transform(data) {
|
||||
return data.map((course) => {
|
||||
course.data = JSON.parse(course.data)
|
||||
return course
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
courses() {
|
||||
console.log(this.courses)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<div class="max-w-3xl py-12 mx-auto">
|
||||
<Button
|
||||
icon-left="code"
|
||||
@click="$resources.ping.fetch"
|
||||
:loading="$resources.ping.loading"
|
||||
>
|
||||
Click to send 'ping' request
|
||||
</Button>
|
||||
<div>
|
||||
{{ $resources.ping.data }}
|
||||
</div>
|
||||
<pre>{{ $resources.ping }}</pre>
|
||||
|
||||
<Button @click="showDialog = true">Open Dialog</Button>
|
||||
<Dialog title="Title" v-model="showDialog"> Dialog content </Dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Dialog } from 'frappe-ui'
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
data() {
|
||||
return {
|
||||
showDialog: false,
|
||||
}
|
||||
},
|
||||
resources: {
|
||||
ping: {
|
||||
url: 'ping',
|
||||
},
|
||||
},
|
||||
components: {
|
||||
Dialog,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: () => import('@/pages/Home.vue'),
|
||||
},
|
||||
{
|
||||
path: '/courses',
|
||||
name: 'Courses',
|
||||
component: () => import('@/pages/Courses.vue'),
|
||||
},
|
||||
]
|
||||
|
||||
let router = createRouter({
|
||||
history: createWebHistory('/'),
|
||||
routes,
|
||||
})
|
||||
|
||||
export default router
|
||||
@@ -0,0 +1,12 @@
|
||||
module.exports = {
|
||||
presets: [require('frappe-ui/src/utils/tailwind.config')],
|
||||
content: [
|
||||
'./index.html',
|
||||
'./src/**/*.{vue,js,ts,jsx,tsx}',
|
||||
'./node_modules/frappe-ui/src/components/**/*.{vue,js,ts,jsx,tsx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
import { getProxyOptions } from 'frappe-ui/src/utils/vite-dev-server'
|
||||
import { webserver_port } from '../../../sites/common_site_config.json'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 8080,
|
||||
proxy: getProxyOptions({ port: webserver_port }),
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: `../${path.basename(path.resolve('..'))}/public/frontend`,
|
||||
emptyOutDir: true,
|
||||
target: 'es2015',
|
||||
},
|
||||
optimizeDeps: {
|
||||
include: ['frappe-ui > feather-icons', 'showdown', 'engine.io-client'],
|
||||
},
|
||||
})
|
||||
+1718
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user