Skip to content

Commit 236bfbb

Browse files
authored
init standalone-ui package (#647)
2 parents c1fa407 + a8b916b commit 236bfbb

File tree

14 files changed

+325
-0
lines changed

14 files changed

+325
-0
lines changed

packages/standalone-ui/index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<link rel="icon" href="/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Skuilder Course</title>
8+
<link
9+
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons"
10+
rel="stylesheet"
11+
/>
12+
</head>
13+
<body>
14+
<div id="app"></div>
15+
<script type="module" src="/src/main.ts"></script>
16+
</body>
17+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@vue-skuilder/standalone-ui",
3+
"version": "0.1.0",
4+
"private": true,
5+
"type": "module",
6+
"scripts": {
7+
"dev": "vite",
8+
"build": "vue-tsc --noEmit && vite build",
9+
"preview": "vite preview"
10+
},
11+
"dependencies": {
12+
"@vue-skuilder/common-ui": "workspace:*",
13+
"@vue-skuilder/db": "workspace:*",
14+
"pinia": "^2.3.0",
15+
"vue": "^3.5.13",
16+
"vue-router": "^4.2.0",
17+
"vuetify": "^3.7.0"
18+
},
19+
"devDependencies": {
20+
"@vitejs/plugin-vue": "^5.2.1",
21+
"typescript": "^5.7.2",
22+
"vite": "^6.0.9",
23+
"vue-tsc": "^1.8.0"
24+
}
25+
}

packages/standalone-ui/src/App.vue

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<template>
2+
<v-app :theme="theme">
3+
<course-header :title="courseConfig.title" :logo="courseConfig.logo" />
4+
5+
<v-main>
6+
<router-view />
7+
</v-main>
8+
9+
<course-footer :links="courseConfig.links" :copyright="courseConfig.copyright" />
10+
</v-app>
11+
</template>
12+
13+
<script setup lang="ts">
14+
import { computed } from 'vue';
15+
import { useCourseConfig } from './composables/useCourseConfig';
16+
import CourseHeader from './components/CourseHeader.vue';
17+
import CourseFooter from './components/CourseFooter.vue';
18+
19+
const { courseConfig } = useCourseConfig();
20+
const theme = computed(() => (courseConfig.darkMode ? 'dark' : 'light'));
21+
</script>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<template>
2+
<v-footer app padless>
3+
<v-container fluid>
4+
<v-row justify="center" align="center">
5+
<v-col cols="12" sm="8" class="text-center">
6+
<div v-if="links && links.length" class="d-flex justify-center mb-2">
7+
<v-btn
8+
v-for="link in links"
9+
:key="link.text"
10+
:href="link.url"
11+
text
12+
variant="plain"
13+
size="small"
14+
class="mx-1"
15+
>
16+
{{ link.text }}
17+
</v-btn>
18+
</div>
19+
<div class="text-body-2 text-medium-emphasis">
20+
{{ copyright }}
21+
</div>
22+
</v-col>
23+
</v-row>
24+
</v-container>
25+
</v-footer>
26+
</template>
27+
28+
<script setup lang="ts">
29+
defineProps<{
30+
links?: Array<{ text: string; url: string }>;
31+
copyright?: string;
32+
}>();
33+
</script>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<template>
2+
<v-app-bar>
3+
<v-app-bar-nav-icon v-if="isMobile"></v-app-bar-nav-icon>
4+
5+
<v-toolbar-title class="d-flex align-center">
6+
<img v-if="logo" :src="logo" alt="Course Logo" height="32" class="mr-2" />
7+
{{ title }}
8+
</v-toolbar-title>
9+
10+
<v-spacer></v-spacer>
11+
12+
<div v-if="!isMobile" class="d-flex">
13+
<v-btn v-for="item in menuItems" :key="item.text" :to="item.path" text>
14+
{{ item.text }}
15+
</v-btn>
16+
</div>
17+
</v-app-bar>
18+
</template>
19+
20+
<script setup lang="ts">
21+
import { ref, computed } from 'vue';
22+
import { useDisplay } from 'vuetify';
23+
24+
const props = defineProps<{
25+
title: string;
26+
logo?: string;
27+
}>();
28+
29+
const { mobile } = useDisplay();
30+
const isMobile = computed(() => mobile.value);
31+
32+
const menuItems = ref([
33+
{ text: 'Home', path: '/' },
34+
{ text: 'Study', path: '/study' },
35+
{ text: 'Progress', path: '/progress' },
36+
]);
37+
</script>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ref, readonly } from 'vue';
2+
3+
// This would be replaced by actual course configuration in a real implementation
4+
const defaultConfig = {
5+
title: 'Course Title',
6+
description: 'Course Description',
7+
logo: '/logo.png',
8+
darkMode: false,
9+
links: [
10+
{ text: 'About', url: '/about' },
11+
{ text: 'Help', url: '/help' }
12+
],
13+
copyright: '© 2025 Skuilder'
14+
};
15+
16+
export function useCourseConfig() {
17+
const courseConfig = ref(defaultConfig);
18+
19+
// Later this would load from a configuration file or API
20+
const loadConfig = async () => {
21+
// In a real implementation, this would load configuration
22+
// courseConfig.value = await loadCourseConfig();
23+
};
24+
25+
// Initialize
26+
loadConfig();
27+
28+
return {
29+
courseConfig: readonly(courseConfig),
30+
loadConfig
31+
};
32+
}

packages/standalone-ui/src/main.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { createApp } from 'vue';
2+
import { createPinia } from 'pinia';
3+
import App from './App.vue';
4+
import router from './router';
5+
6+
// Vuetify
7+
import 'vuetify/styles';
8+
import { createVuetify } from 'vuetify';
9+
import * as components from 'vuetify/components';
10+
import * as directives from 'vuetify/directives';
11+
12+
const vuetify = createVuetify({
13+
components,
14+
directives,
15+
theme: {
16+
defaultTheme: 'light',
17+
},
18+
});
19+
20+
const app = createApp(App);
21+
22+
app.use(createPinia());
23+
app.use(router);
24+
app.use(vuetify);
25+
26+
app.mount('#app');
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
2+
import HomeView from '../views/HomeView.vue';
3+
import StudyView from '../views/StudyView.vue';
4+
import ProgressView from '../views/ProgressView.vue';
5+
6+
const routes: Array<RouteRecordRaw> = [
7+
{
8+
path: '/',
9+
name: 'home',
10+
component: HomeView,
11+
},
12+
{
13+
path: '/study',
14+
name: 'study',
15+
component: StudyView,
16+
},
17+
{
18+
path: '/progress',
19+
name: 'progress',
20+
component: ProgressView,
21+
},
22+
];
23+
24+
const router = createRouter({
25+
history: createWebHistory(),
26+
routes,
27+
});
28+
29+
export default router;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<template>
2+
<v-container>
3+
<v-row>
4+
<v-col cols="12" class="text-center">
5+
<h1 class="text-h3 mb-6">{{ courseConfig.title }}</h1>
6+
<p class="text-body-1 mb-6">{{ courseConfig.description }}</p>
7+
<v-btn color="primary" size="large" to="/study"> Start Learning </v-btn>
8+
</v-col>
9+
</v-row>
10+
</v-container>
11+
</template>
12+
13+
<script setup lang="ts">
14+
import { useCourseConfig } from '../composables/useCourseConfig';
15+
16+
const { courseConfig } = useCourseConfig();
17+
</script>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<template>
2+
<v-container>
3+
<v-row>
4+
<v-col cols="12">
5+
<h1 class="text-h4 mb-4">Your Progress</h1>
6+
7+
<!-- Placeholder for progress component -->
8+
<v-card class="pa-4">
9+
<p>Progress tracking will be shown here.</p>
10+
</v-card>
11+
</v-col>
12+
</v-row>
13+
</v-container>
14+
</template>
15+
16+
<script setup lang="ts">
17+
// Would import from common-ui or db package
18+
</script>

0 commit comments

Comments
 (0)