fix: persistent favicon for all pages

This commit is contained in:
Jannat Patel
2025-04-08 10:57:02 +05:30
parent c70da08078
commit 5d1673bad8
35 changed files with 307 additions and 175 deletions

View File

@@ -142,6 +142,7 @@
</div> </div>
</div> </div>
<ChapterModal <ChapterModal
v-if="user.data"
v-model="showChapterModal" v-model="showChapterModal"
v-model:outline="outline" v-model:outline="outline"
:course="courseName" :course="courseName"

View File

@@ -1,7 +1,7 @@
<template> <template>
<div v-if="quiz.data"> <div v-if="quiz.data">
<div <div
class="bg-surface-blue-2 space-y-1 py-2 px-2 mb-4 rounded-md text-sm text-ink-blue-2" class="bg-surface-blue-2 space-y-1 py-2 px-2 mb-4 rounded-md text-sm text-ink-blue-3"
> >
<div class="leading-5"> <div class="leading-5">
{{ {{

View File

@@ -63,6 +63,7 @@ import {
createResource, createResource,
FormControl, FormControl,
TextEditor, TextEditor,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { import {
computed, computed,
@@ -72,11 +73,13 @@ import {
reactive, reactive,
watch, watch,
} from 'vue' } from 'vue'
import { sessionStore } from '../stores/session'
import { showToast } from '@/utils' import { showToast } from '@/utils'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const user = inject('$user') const user = inject('$user')
const router = useRouter() const router = useRouter()
const { brand } = sessionStore()
const props = defineProps({ const props = defineProps({
assignmentID: { assignmentID: {
@@ -188,4 +191,11 @@ const assignmentOptions = computed(() => {
{ label: 'URL', value: 'URL' }, { label: 'URL', value: 'URL' },
] ]
}) })
usePageMeta(() => {
return {
title: assignment.doc ? assignment.doc.title : __('New Assignment'),
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -14,12 +14,14 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { Breadcrumbs, createResource } from 'frappe-ui' import { Breadcrumbs, createResource, usePageMeta } from 'frappe-ui'
import { computed, inject, onMounted, onBeforeUnmount, ref } from 'vue' import { computed, inject, onMounted, ref } from 'vue'
import { sessionStore } from '../stores/session'
import Assignment from '@/components/Assignment.vue' import Assignment from '@/components/Assignment.vue'
const user = inject('$user') const user = inject('$user')
const fromLesson = ref(false) const fromLesson = ref(false)
const { brand } = sessionStore()
const props = defineProps({ const props = defineProps({
assignmentID: { assignmentID: {
@@ -72,4 +74,11 @@ const breadcrumbs = computed(() => {
] ]
return crumbs return crumbs
}) })
usePageMeta(() => {
return {
title: title.data?.title,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -84,14 +84,17 @@ import {
ListRows, ListRows,
ListRow, ListRow,
ListRowItem, ListRowItem,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, inject, onMounted, ref, watch } from 'vue' import { computed, inject, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { Pencil } from 'lucide-vue-next' import { Pencil } from 'lucide-vue-next'
import { sessionStore } from '../stores/session'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
const user = inject('$user') const user = inject('$user')
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
const { brand } = sessionStore()
const router = useRouter() const router = useRouter()
const assignmentID = ref('') const assignmentID = ref('')
const member = ref('') const member = ref('')
@@ -214,4 +217,11 @@ const breadcrumbs = computed(() => {
}, },
] ]
}) })
usePageMeta(() => {
return {
title: __('Assignment Submissions'),
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -80,15 +80,18 @@ import {
createListResource, createListResource,
FormControl, FormControl,
ListView, ListView,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, inject, onMounted, ref, watch } from 'vue' import { computed, inject, onMounted, ref, watch } from 'vue'
import { Plus, Pencil } from 'lucide-vue-next' import { Plus, Pencil } from 'lucide-vue-next'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { sessionStore } from '../stores/session'
const user = inject('$user') const user = inject('$user')
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
const titleFilter = ref('') const titleFilter = ref('')
const typeFilter = ref('') const typeFilter = ref('')
const { brand } = sessionStore()
const router = useRouter() const router = useRouter()
onMounted(() => { onMounted(() => {
@@ -184,4 +187,11 @@ const breadcrumbs = computed(() => [
route: { name: 'Assignments' }, route: { name: 'Assignments' },
}, },
]) ])
usePageMeta(() => {
return {
title: __('Assignments'),
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -24,10 +24,12 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { createDocumentResource, createResource } from 'frappe-ui' import { createResource, usePageMeta } from 'frappe-ui'
import { computed, inject } from 'vue' import { computed, inject } from 'vue'
import { sessionStore } from '../stores/session'
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
const { brand } = sessionStore()
const props = defineProps({ const props = defineProps({
badgeName: { badgeName: {
@@ -70,4 +72,11 @@ const breadcrumbs = computed(() => {
}, },
] ]
}) })
usePageMeta(() => {
return {
title: badge.data.badge,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -199,9 +199,14 @@
<script setup> <script setup>
import { computed, inject, ref, onMounted, watch } from 'vue' import { computed, inject, ref, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { Breadcrumbs, Button, createResource, Tabs, Badge } from 'frappe-ui' import {
import CourseInstructors from '@/components/CourseInstructors.vue' Breadcrumbs,
import UserAvatar from '@/components/UserAvatar.vue' Button,
createResource,
Tabs,
Badge,
usePageMeta,
} from 'frappe-ui'
import { import {
Clock, Clock,
LayoutDashboard, LayoutDashboard,
@@ -214,7 +219,10 @@ import {
Globe, Globe,
ClipboardPen, ClipboardPen,
} from 'lucide-vue-next' } from 'lucide-vue-next'
import { formatTime, updateDocumentTitle } from '@/utils' import { formatTime } from '@/utils'
import { sessionStore } from '@/stores/session'
import CourseInstructors from '@/components/CourseInstructors.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import BatchDashboard from '@/components/BatchDashboard.vue' import BatchDashboard from '@/components/BatchDashboard.vue'
import BatchCourses from '@/components/BatchCourses.vue' import BatchCourses from '@/components/BatchCourses.vue'
import LiveClass from '@/components/LiveClass.vue' import LiveClass from '@/components/LiveClass.vue'
@@ -232,6 +240,7 @@ const showAnnouncementModal = ref(false)
const openCertificateDialog = ref(false) const openCertificateDialog = ref(false)
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const { brand } = sessionStore()
const tabIndex = ref(0) const tabIndex = ref(0)
const tabs = computed(() => { const tabs = computed(() => {
@@ -345,12 +354,10 @@ watch(tabIndex, () => {
} }
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: batch.data?.title, title: batch?.data?.title,
description: batch.data?.description, icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -102,8 +102,9 @@
import { computed, inject } from 'vue' import { computed, inject } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { BookOpen, Clock } from 'lucide-vue-next' import { BookOpen, Clock } from 'lucide-vue-next'
import { formatTime, updateDocumentTitle } from '@/utils' import { formatTime } from '@/utils'
import { Breadcrumbs, createResource } from 'frappe-ui' import { Breadcrumbs, createResource, usePageMeta } from 'frappe-ui'
import { sessionStore } from '@/stores/session'
import CourseCard from '@/components/CourseCard.vue' import CourseCard from '@/components/CourseCard.vue'
import BatchOverlay from '@/components/BatchOverlay.vue' import BatchOverlay from '@/components/BatchOverlay.vue'
import DateRange from '../components/Common/DateRange.vue' import DateRange from '../components/Common/DateRange.vue'
@@ -112,6 +113,7 @@ import UserAvatar from '@/components/UserAvatar.vue'
const user = inject('$user') const user = inject('$user')
const router = useRouter() const router = useRouter()
const { brand } = sessionStore()
const props = defineProps({ const props = defineProps({
batchName: { batchName: {
@@ -152,14 +154,12 @@ const breadcrumbs = computed(() => {
return items return items
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: batch.data?.title, title: batch?.data?.title,
description: batch.data?.description, icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>
<style> <style>
.batch-description p { .batch-description p {

View File

@@ -264,17 +264,20 @@ import {
Button, Button,
TextEditor, TextEditor,
createResource, createResource,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import Link from '@/components/Controls/Link.vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { showToast } from '@/utils' import { showToast } from '@/utils'
import { Image } from 'lucide-vue-next' import { Image } from 'lucide-vue-next'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
import { useOnboarding } from 'frappe-ui/frappe' import { useOnboarding } from 'frappe-ui/frappe'
import { sessionStore } from '../stores/session'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
import Link from '@/components/Controls/Link.vue'
const router = useRouter() const router = useRouter()
const user = inject('$user') const user = inject('$user')
const { brand } = sessionStore()
const { updateOnboardingStep } = useOnboarding('learning') const { updateOnboardingStep } = useOnboarding('learning')
const props = defineProps({ const props = defineProps({
@@ -505,4 +508,11 @@ const breadcrumbs = computed(() => {
}) })
return crumbs return crumbs
}) })
usePageMeta(() => {
return {
title: props.batchName == 'new' ? 'New Batch' : batchDetail.data?.title,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -104,14 +104,16 @@ import {
FormControl, FormControl,
Select, Select,
TabButtons, TabButtons,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, inject, onMounted, ref, watch } from 'vue' import { computed, inject, onMounted, ref, watch } from 'vue'
import { BookOpen, Plus } from 'lucide-vue-next' import { BookOpen, Plus } from 'lucide-vue-next'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '@/stores/session'
import BatchCard from '@/components/BatchCard.vue' import BatchCard from '@/components/BatchCard.vue'
const user = inject('$user') const user = inject('$user')
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
const { brand } = sessionStore()
const start = ref(0) const start = ref(0)
const pageLength = ref(20) const pageLength = ref(20)
const categories = ref([]) const categories = ref([])
@@ -304,12 +306,10 @@ const breadcrumbs = computed(() => [
}, },
]) ])
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Batches', title: __('Batches'),
description: 'All upcoming batches.', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -151,19 +151,20 @@
</template> </template>
<script setup> <script setup>
import { import {
Input,
Button, Button,
createResource, createResource,
FormControl, FormControl,
Breadcrumbs, Breadcrumbs,
Tooltip, usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { reactive, inject, onMounted, computed } from 'vue' import { reactive, inject, onMounted, computed } from 'vue'
import { showToast } from '@/utils/'
import { sessionStore } from '../stores/session'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import NotPermitted from '@/components/NotPermitted.vue' import NotPermitted from '@/components/NotPermitted.vue'
import { showToast } from '@/utils/'
const user = inject('$user') const user = inject('$user')
const { brand } = sessionStore()
onMounted(() => { onMounted(() => {
const script = document.createElement('script') const script = document.createElement('script')
@@ -356,4 +357,11 @@ const redirectTo = computed(() => {
return `/lms/courses/${props.name}/certification` return `/lms/courses/${props.name}/certification`
} }
}) })
usePageMeta(() => {
return {
title: __('Billing Details'),
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -102,14 +102,17 @@ import {
createListResource, createListResource,
FormControl, FormControl,
Select, Select,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, onMounted, ref } from 'vue' import { computed, onMounted, ref } from 'vue'
import { updateDocumentTitle } from '@/utils' import { updateDocumentTitle } from '@/utils'
import { BookOpen, GraduationCap } from 'lucide-vue-next' import { BookOpen, GraduationCap } from 'lucide-vue-next'
import { sessionStore } from '../stores/session'
const currentCategory = ref('') const currentCategory = ref('')
const filters = ref({}) const filters = ref({})
const nameFilter = ref('') const nameFilter = ref('')
const { brand } = sessionStore()
onMounted(() => { onMounted(() => {
updateParticipants() updateParticipants()
@@ -163,13 +166,12 @@ const breadcrumbs = computed(() => [
}, },
]) ])
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Certified Participants', title: __('Certified Participants'),
description: 'All participants that have been certified.', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>
<style> <style>
.headline { .headline {

View File

@@ -36,12 +36,14 @@
</template> </template>
<script setup> <script setup>
import { computed, inject, onMounted, ref } from 'vue' import { computed, inject, onMounted, ref } from 'vue'
import { Breadcrumbs, call, createResource } from 'frappe-ui' import { Breadcrumbs, call, createResource, usePageMeta } from 'frappe-ui'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { sessionStore } from '../stores/session'
import UpcomingEvaluations from '@/components/UpcomingEvaluations.vue' import UpcomingEvaluations from '@/components/UpcomingEvaluations.vue'
const courseTitle = ref(null) const courseTitle = ref(null)
const evaluator = ref(null) const evaluator = ref(null)
const { brand } = sessionStore()
const courses = ref([]) const courses = ref([])
const user = inject('$user') const user = inject('$user')
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
@@ -133,4 +135,11 @@ const breadcrumbs = computed(() => [
label: __('Certification'), label: __('Certification'),
}, },
]) ])
usePageMeta(() => {
return {
title: courseTitle.value,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -92,16 +92,24 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { createResource, Breadcrumbs, Badge, Tooltip } from 'frappe-ui' import {
createResource,
Breadcrumbs,
Badge,
Tooltip,
usePageMeta,
} from 'frappe-ui'
import { computed } from 'vue' import { computed } from 'vue'
import { Users, Star } from 'lucide-vue-next' import { Users, Star } from 'lucide-vue-next'
import { sessionStore } from '@/stores/session'
import CourseCardOverlay from '@/components/CourseCardOverlay.vue' import CourseCardOverlay from '@/components/CourseCardOverlay.vue'
import CourseOutline from '@/components/CourseOutline.vue' import CourseOutline from '@/components/CourseOutline.vue'
import CourseReviews from '@/components/CourseReviews.vue' import CourseReviews from '@/components/CourseReviews.vue'
import UserAvatar from '@/components/UserAvatar.vue' import UserAvatar from '@/components/UserAvatar.vue'
import { updateDocumentTitle } from '@/utils'
import CourseInstructors from '@/components/CourseInstructors.vue' import CourseInstructors from '@/components/CourseInstructors.vue'
const { brand } = sessionStore()
const props = defineProps({ const props = defineProps({
courseName: { courseName: {
type: String, type: String,
@@ -127,14 +135,12 @@ const breadcrumbs = computed(() => {
return items return items
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: course?.data?.title, title: course?.data?.title,
description: course?.data?.short_introduction, icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>
<style> <style>
.avatar-group { .avatar-group {

View File

@@ -253,6 +253,7 @@ import {
createResource, createResource,
FormControl, FormControl,
FileUploader, FileUploader,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { import {
inject, inject,
@@ -265,17 +266,19 @@ import {
getCurrentInstance, getCurrentInstance,
} from 'vue' } from 'vue'
import { showToast, updateDocumentTitle } from '@/utils' import { showToast, updateDocumentTitle } from '@/utils'
import Link from '@/components/Controls/Link.vue'
import { Image, Trash2, X } from 'lucide-vue-next' import { Image, Trash2, X } from 'lucide-vue-next'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import CourseOutline from '@/components/CourseOutline.vue'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { useOnboarding } from 'frappe-ui/frappe' import { useOnboarding } from 'frappe-ui/frappe'
import { sessionStore } from '../stores/session'
import { useSettings } from '@/stores/settings' import { useSettings } from '@/stores/settings'
import Link from '@/components/Controls/Link.vue'
import CourseOutline from '@/components/CourseOutline.vue'
import MultiSelect from '@/components/Controls/MultiSelect.vue'
const user = inject('$user') const user = inject('$user')
const newTag = ref('') const newTag = ref('')
const { brand } = sessionStore()
const router = useRouter() const router = useRouter()
const instructors = ref([]) const instructors = ref([])
const settingsStore = useSettings() const settingsStore = useSettings()
@@ -574,12 +577,10 @@ const breadcrumbs = computed(() => {
return crumbs return crumbs
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Create a Course', title: courseResource.data?.title || __('New Course'),
description: 'Create or edit a course for your learning system.', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -100,10 +100,11 @@ import {
FormControl, FormControl,
Select, Select,
TabButtons, TabButtons,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, inject, onMounted, ref, watch } from 'vue' import { computed, inject, onMounted, ref, watch } from 'vue'
import { BookOpen, Plus } from 'lucide-vue-next' import { BookOpen, Plus } from 'lucide-vue-next'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '@/stores/session'
import CourseCard from '@/components/CourseCard.vue' import CourseCard from '@/components/CourseCard.vue'
const user = inject('$user') const user = inject('$user')
@@ -116,6 +117,7 @@ const title = ref('')
const certification = ref(false) const certification = ref(false)
const filters = ref({}) const filters = ref({})
const currentTab = ref('Live') const currentTab = ref('Live')
const { brand } = sessionStore()
onMounted(() => { onMounted(() => {
setFiltersFromQuery() setFiltersFromQuery()
@@ -303,12 +305,10 @@ const breadcrumbs = computed(() => [
}, },
]) ])
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Courses', title: __('Courses'),
description: 'All published courses.', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -1,39 +0,0 @@
<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>

View File

@@ -139,14 +139,17 @@ import {
Button, Button,
TextEditor, TextEditor,
FileUploader, FileUploader,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, onMounted, reactive, inject } from 'vue' import { computed, onMounted, reactive, inject } from 'vue'
import { FileText, X } from 'lucide-vue-next' import { FileText, X } from 'lucide-vue-next'
import { sessionStore } from '@/stores/session'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { getFileSize, showToast } from '../utils' import { getFileSize, showToast } from '../utils'
const user = inject('$user') const user = inject('$user')
const router = useRouter() const router = useRouter()
const { brand } = sessionStore()
const props = defineProps({ const props = defineProps({
jobName: { jobName: {
@@ -319,4 +322,11 @@ const breadcrumbs = computed(() => {
] ]
return crumbs return crumbs
}) })
usePageMeta(() => {
return {
title: props.jobName == 'new' ? 'New Job' : jobDetail.data?.title,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -142,9 +142,9 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { Button, Breadcrumbs, createResource } from 'frappe-ui' import { Button, Breadcrumbs, createResource, usePageMeta } from 'frappe-ui'
import { inject, ref, computed } from 'vue' import { inject, ref } from 'vue'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '../stores/session'
import JobApplicationModal from '@/components/Modals/JobApplicationModal.vue' import JobApplicationModal from '@/components/Modals/JobApplicationModal.vue'
import { import {
MapPin, MapPin,
@@ -158,6 +158,7 @@ import {
const user = inject('$user') const user = inject('$user')
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
const { brand } = sessionStore()
const showApplicationModal = ref(false) const showApplicationModal = ref(false)
const props = defineProps({ const props = defineProps({
@@ -215,12 +216,10 @@ const redirectToLogin = (job) => {
window.location.href = `/login?redirect-to=/job-openings/${job}` window.location.href = `/login?redirect-to=/job-openings/${job}`
} }
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: job.data?.job_title, title: job.data?.job_title,
description: job.data?.description, icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -81,14 +81,21 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { Button, Breadcrumbs, createResource, FormControl } from 'frappe-ui' import {
Button,
Breadcrumbs,
createResource,
FormControl,
usePageMeta,
} from 'frappe-ui'
import { Plus, Search } from 'lucide-vue-next' import { Plus, Search } from 'lucide-vue-next'
import { sessionStore } from '../stores/session'
import { inject, computed, ref, onMounted } from 'vue' import { inject, computed, ref, onMounted } from 'vue'
import JobCard from '@/components/JobCard.vue' import JobCard from '@/components/JobCard.vue'
import { updateDocumentTitle } from '@/utils'
const user = inject('$user') const user = inject('$user')
const jobType = ref(null) const jobType = ref(null)
const { brand } = sessionStore()
const searchQuery = ref('') const searchQuery = ref('')
const filters = ref({}) const filters = ref({})
const orFilters = ref({}) const orFilters = ref({})
@@ -147,12 +154,11 @@ const jobTypes = computed(() => {
{ label: __('Freelance'), value: 'Freelance' }, { label: __('Freelance'), value: 'Freelance' },
] ]
}) })
const pageMeta = computed(() => {
usePageMeta(() => {
return { return {
title: 'Jobs', title: __('Jobs'),
description: 'An open job board for the community', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -193,14 +193,15 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { createResource, Breadcrumbs, Button } from 'frappe-ui' import { createResource, Breadcrumbs, Button, usePageMeta } from 'frappe-ui'
import { computed, watch, inject, ref, onMounted, onBeforeUnmount } from 'vue' import { computed, watch, inject, ref, onMounted, onBeforeUnmount } from 'vue'
import CourseOutline from '@/components/CourseOutline.vue' import CourseOutline from '@/components/CourseOutline.vue'
import UserAvatar from '@/components/UserAvatar.vue' import UserAvatar from '@/components/UserAvatar.vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { ChevronLeft, ChevronRight, GraduationCap } from 'lucide-vue-next' import { ChevronLeft, ChevronRight, GraduationCap } from 'lucide-vue-next'
import Discussions from '@/components/Discussions.vue' import Discussions from '@/components/Discussions.vue'
import { getEditorTools, updateDocumentTitle } from '../utils' import { getEditorTools } from '../utils'
import { sessionStore } from '@/stores/session'
import EditorJS from '@editorjs/editorjs' import EditorJS from '@editorjs/editorjs'
import LessonContent from '@/components/LessonContent.vue' import LessonContent from '@/components/LessonContent.vue'
import CourseInstructors from '@/components/CourseInstructors.vue' import CourseInstructors from '@/components/CourseInstructors.vue'
@@ -215,6 +216,7 @@ const editor = ref(null)
const instructorEditor = ref(null) const instructorEditor = ref(null)
const lessonProgress = ref(0) const lessonProgress = ref(0)
const timer = ref(0) const timer = ref(0)
const { brand } = sessionStore()
let timerInterval let timerInterval
const props = defineProps({ const props = defineProps({
@@ -419,14 +421,12 @@ const redirectToLogin = () => {
window.location.href = `/login?redirect-to=/lms/courses/${props.courseName}` window.location.href = `/login?redirect-to=/lms/courses/${props.courseName}`
} }
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: lesson.data?.title, title: lesson?.data?.title,
description: lesson.data?.course, icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>
<style> <style>
.avatar-group { .avatar-group {

View File

@@ -78,7 +78,13 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { Breadcrumbs, Button, createResource, FormControl } from 'frappe-ui' import {
Breadcrumbs,
Button,
createResource,
FormControl,
usePageMeta,
} from 'frappe-ui'
import { import {
computed, computed,
reactive, reactive,
@@ -87,13 +93,15 @@ import {
ref, ref,
onBeforeUnmount, onBeforeUnmount,
} from 'vue' } from 'vue'
import { sessionStore } from '../stores/session'
import EditorJS from '@editorjs/editorjs' import EditorJS from '@editorjs/editorjs'
import LessonHelp from '@/components/LessonHelp.vue' import LessonHelp from '@/components/LessonHelp.vue'
import { ChevronRight } from 'lucide-vue-next' import { ChevronRight } from 'lucide-vue-next'
import { updateDocumentTitle, createToast, getEditorTools } from '@/utils' import { createToast, getEditorTools } from '@/utils'
import { capture } from '@/telemetry' import { capture } from '@/telemetry'
import { useOnboarding } from 'frappe-ui/frappe' import { useOnboarding } from 'frappe-ui/frappe'
const { brand } = sessionStore()
const editor = ref(null) const editor = ref(null)
const instructorEditor = ref(null) const instructorEditor = ref(null)
const user = inject('$user') const user = inject('$user')
@@ -492,14 +500,14 @@ const breadcrumbs = computed(() => {
return crumbs return crumbs
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Lesson Editor', title: lessonDetails?.data?.lesson
description: 'Create and edit lessons for your course', ? lessonDetails.data.lesson.title
: 'New Lesson',
icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>
<style> <style>
.embed-tool__caption, .embed-tool__caption,

View File

@@ -65,12 +65,14 @@ import {
TabButtons, TabButtons,
Button, Button,
Tooltip, Tooltip,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { sessionStore } from '../stores/session'
import { computed, inject, ref, onMounted } from 'vue' import { computed, inject, ref, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { X } from 'lucide-vue-next' import { X } from 'lucide-vue-next'
import { updateDocumentTitle } from '@/utils'
const { brand } = sessionStore()
const user = inject('$user') const user = inject('$user')
const socket = inject('$socket') const socket = inject('$socket')
const activeTab = ref('Unread') const activeTab = ref('Unread')
@@ -145,14 +147,12 @@ const breadcrumbs = computed(() => {
return crumbs return crumbs
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Notifications', title: 'Notifications',
description: 'All your notifications in one place.', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>
<style> <style>
.notification strong { .notification strong {

View File

@@ -86,18 +86,24 @@
/> />
</template> </template>
<script setup> <script setup>
import { Breadcrumbs, createResource, Button, TabButtons } from 'frappe-ui' import {
Breadcrumbs,
createResource,
Button,
TabButtons,
usePageMeta,
} from 'frappe-ui'
import { computed, inject, watch, ref, onMounted, watchEffect } from 'vue' import { computed, inject, watch, ref, onMounted, watchEffect } from 'vue'
import { sessionStore } from '@/stores/session' import { sessionStore } from '@/stores/session'
import { Edit } from 'lucide-vue-next' import { Edit, icons } from 'lucide-vue-next'
import UserAvatar from '@/components/UserAvatar.vue' import UserAvatar from '@/components/UserAvatar.vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import NoPermission from '@/components/NoPermission.vue' import NoPermission from '@/components/NoPermission.vue'
import { convertToTitleCase, updateDocumentTitle } from '@/utils' import { convertToTitleCase } from '@/utils'
import EditProfile from '@/components/Modals/EditProfile.vue' import EditProfile from '@/components/Modals/EditProfile.vue'
import EditCoverImage from '@/components/Modals/EditCoverImage.vue' import EditCoverImage from '@/components/Modals/EditCoverImage.vue'
const { user } = sessionStore() const { user, brand } = sessionStore()
const $user = inject('$user') const $user = inject('$user')
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@@ -215,12 +221,10 @@ const breadcrumbs = computed(() => {
return crumbs return crumbs
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: profile.data?.full_name, title: profile.data?.full_name,
description: profile.data?.headline, icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -186,14 +186,17 @@ import {
ListHeader, ListHeader,
ListHeaderItem, ListHeaderItem,
ListSelectBanner, ListSelectBanner,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
import { Plus, Trash2 } from 'lucide-vue-next' import { Plus, Trash2 } from 'lucide-vue-next'
import Link from '@/components/Controls/Link.vue'
import { showToast } from '@/utils/' import { showToast } from '@/utils/'
import Draggable from 'vuedraggable'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { sessionStore } from '../stores/session'
import Draggable from 'vuedraggable'
import Link from '@/components/Controls/Link.vue'
const { brand } = sessionStore()
const showDialog = ref(false) const showDialog = ref(false)
const currentForm = ref(null) const currentForm = ref(null)
const course = ref(null) const course = ref(null)
@@ -364,4 +367,11 @@ const breadbrumbs = computed(() => {
}, },
] ]
}) })
usePageMeta(() => {
return {
title: program.doc?.title,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -126,14 +126,17 @@ import {
createResource, createResource,
Dialog, Dialog,
FormControl, FormControl,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, inject, onMounted, ref } from 'vue' import { computed, inject, onMounted, ref } from 'vue'
import { BookOpen, Edit, Plus, LockKeyhole } from 'lucide-vue-next' import { BookOpen, Edit, Plus, LockKeyhole } from 'lucide-vue-next'
import CourseCard from '@/components/CourseCard.vue' import CourseCard from '@/components/CourseCard.vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { sessionStore } from '../stores/session'
import { showToast } from '@/utils' import { showToast } from '@/utils'
import { useSettings } from '@/stores/settings' import { useSettings } from '@/stores/settings'
const { brand } = sessionStore()
const user = inject('$user') const user = inject('$user')
const showDialog = ref(false) const showDialog = ref(false)
const router = useRouter() const router = useRouter()
@@ -210,4 +213,11 @@ const breadbrumbs = computed(() => [
label: 'Programs', label: 'Programs',
}, },
]) ])
usePageMeta(() => {
return {
title: __('Programs'),
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -197,6 +197,7 @@ import {
ListRowItem, ListRowItem,
ListSelectBanner, ListSelectBanner,
Button, Button,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { import {
computed, computed,
@@ -207,11 +208,13 @@ import {
onBeforeUnmount, onBeforeUnmount,
watch, watch,
} from 'vue' } from 'vue'
import { sessionStore } from '../stores/session'
import { Plus, Trash2 } from 'lucide-vue-next' import { Plus, Trash2 } from 'lucide-vue-next'
import Question from '@/components/Modals/Question.vue'
import { showToast, updateDocumentTitle } from '@/utils' import { showToast, updateDocumentTitle } from '@/utils'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import Question from '@/components/Modals/Question.vue'
const { brand } = sessionStore()
const showQuestionModal = ref(false) const showQuestionModal = ref(false)
const currentQuestion = reactive({ const currentQuestion = reactive({
question: '', question: '',
@@ -453,12 +456,10 @@ const breadcrumbs = computed(() => {
return crumbs return crumbs
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: props.quizID == 'new' ? __('New Quiz') : quizDetails.data?.title, title: props.quizID == 'new' ? __('New Quiz') : quizDetails.data?.title,
description: __('Form to create and edit quizzes'), icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -14,11 +14,12 @@
</template> </template>
<script setup> <script setup>
import Quiz from '@/components/Quiz.vue' import Quiz from '@/components/Quiz.vue'
import { createResource, Breadcrumbs } from 'frappe-ui' import { createResource, Breadcrumbs, usePageMeta } from 'frappe-ui'
import { computed, inject, onMounted, ref } from 'vue' import { computed, inject, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '../stores/session'
const { brand } = sessionStore()
const user = inject('$user') const user = inject('$user')
const router = useRouter() const router = useRouter()
const fromLesson = ref(false) const fromLesson = ref(false)
@@ -56,12 +57,10 @@ const breadcrumbs = computed(() => {
return [{ label: __('Quiz Submission') }, { label: title.data?.title }] return [{ label: __('Quiz Submission') }, { label: title.data?.title }]
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: title.data?.title, title: `${title.data?.title}`,
description: __('Quiz Submission'), icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -80,10 +80,12 @@ import {
Button, Button,
Badge, Badge,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, onBeforeUnmount, onMounted, inject } from 'vue' import { computed, onBeforeUnmount, onMounted, inject, usePageMeta } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { showToast } from '@/utils' import { showToast } from '@/utils'
import { sessionStore } from '@/stores/session'
const { brand } = sessionStore()
const router = useRouter() const router = useRouter()
const user = inject('$user') const user = inject('$user')
@@ -149,4 +151,11 @@ const saveSubmission = () => {
} }
) )
} }
usePageMeta(() => {
return {
title: `${submisisonDetails.doc.quiz_title}`,
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -40,6 +40,18 @@
</Button> </Button>
</div> </div>
</div> </div>
<div
v-else
class="text-center p-5 text-ink-gray-5 mt-52 w-3/4 md:w-1/2 mx-auto space-y-2"
>
<BookOpen class="size-10 mx-auto stroke-1 text-ink-gray-4" />
<div class="text-xl font-medium">
{{ __('No submissions') }}
</div>
<div class="leading-5">
{{ __('No quiz submissions found. Please check again later.') }}
</div>
</div>
</template> </template>
<script setup> <script setup>
import { import {
@@ -51,10 +63,14 @@ import {
ListRows, ListRows,
ListHeader, ListHeader,
ListHeaderItem, ListHeaderItem,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { BookOpen } from 'lucide-vue-next'
import { computed, onMounted, inject } from 'vue' import { computed, onMounted, inject } from 'vue'
import { sessionStore } from '../stores/session'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const { brand } = sessionStore()
const router = useRouter() const router = useRouter()
const user = inject('$user') const user = inject('$user')
@@ -105,4 +121,11 @@ const quizColumns = computed(() => {
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
return [{ label: __('Quiz Submissions') }] return [{ label: __('Quiz Submissions') }]
}) })
usePageMeta(() => {
return {
title: __('Quiz Submissions'),
icon: brand.favicon,
}
})
</script> </script>

View File

@@ -79,12 +79,14 @@ import {
ListRow, ListRow,
ListHeader, ListHeader,
ListHeaderItem, ListHeaderItem,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { computed, inject, onMounted } from 'vue' import { computed, inject, onMounted } from 'vue'
import { BookOpen, Plus } from 'lucide-vue-next' import { BookOpen, Plus } from 'lucide-vue-next'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '@/stores/session'
const { brand } = sessionStore()
const user = inject('$user') const user = inject('$user')
const router = useRouter() const router = useRouter()
@@ -143,12 +145,10 @@ const breadcrumbs = computed(() => {
] ]
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: __('Quizzes'), title: __('Quizzes'),
description: __('List of quizzes'), icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -39,11 +39,13 @@ import {
createDocumentResource, createDocumentResource,
createListResource, createListResource,
createResource, createResource,
usePageMeta,
} from 'frappe-ui' } from 'frappe-ui'
import { computed, inject, onBeforeMount, ref } from 'vue' import { computed, inject, onBeforeMount, ref } from 'vue'
import { useSidebar } from '@/stores/sidebar' import { useSidebar } from '@/stores/sidebar'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '../stores/session'
const { brand } = sessionStore()
const sidebarStore = useSidebar() const sidebarStore = useSidebar()
const user = inject('$user') const user = inject('$user')
const readyToRender = ref(false) const readyToRender = ref(false)
@@ -195,14 +197,10 @@ const breadcrumbs = computed(() => {
] ]
}) })
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: chapter?.doc?.title, title: chapter.doc?.title,
description: __('This is a chapter in the course {0}').format( icon: brand.favicon,
chapter?.doc?.course_title
),
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -117,9 +117,9 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { createResource, Breadcrumbs } from 'frappe-ui' import { createResource, Breadcrumbs, usePageMeta } from 'frappe-ui'
import { computed, inject } from 'vue' import { computed } from 'vue'
import { updateDocumentTitle } from '@/utils' import { sessionStore } from '../stores/session'
import { formatNumber } from '@/utils' import { formatNumber } from '@/utils'
import { Line, Pie } from 'vue-chartjs' import { Line, Pie } from 'vue-chartjs'
import { import {
@@ -154,7 +154,7 @@ import {
BookOpenCheck, BookOpenCheck,
} from 'lucide-vue-next' } from 'lucide-vue-next'
const dayjs = inject('$dayjs') const { brand } = sessionStore()
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
return [ return [
@@ -317,12 +317,10 @@ const chartOptions = (isPie) => {
} }
} }
const pageMeta = computed(() => { usePageMeta(() => {
return { return {
title: 'Statistics', title: __('Statistics'),
description: 'Statistics of the platform', icon: brand.favicon,
} }
}) })
updateDocumentTitle(pageMeta)
</script> </script>

View File

@@ -2,10 +2,11 @@ import { defineStore } from 'pinia'
import { createResource } from 'frappe-ui' import { createResource } from 'frappe-ui'
import { usersStore } from './user' import { usersStore } from './user'
import router from '@/router' import router from '@/router'
import { ref, computed } from 'vue' import { computed, reactive, ref } from 'vue'
export const sessionStore = defineStore('lms-session', () => { export const sessionStore = defineStore('lms-session', () => {
let { userResource } = usersStore() let { userResource } = usersStore()
const brand = reactive({})
function sessionUser() { function sessionUser() {
let cookies = new URLSearchParams(document.cookie.split('; ').join('&')) let cookies = new URLSearchParams(document.cookie.split('; ').join('&'))
@@ -46,7 +47,9 @@ export const sessionStore = defineStore('lms-session', () => {
cache: 'brand', cache: 'brand',
auto: true, auto: true,
onSuccess(data) { onSuccess(data) {
document.querySelector("link[rel='icon']").href = data.favicon brand.name = data.app_name
brand.logo = data.app_logo
brand.favicon = data.favicon.file_url
}, },
}) })
@@ -61,6 +64,7 @@ export const sessionStore = defineStore('lms-session', () => {
isLoggedIn, isLoggedIn,
login, login,
logout, logout,
brand,
branding, branding,
sidebarSettings, sidebarSettings,
} }