Merge pull request 'Training-Report-Visuals' (#131) from Training-Report-Visuals into main
Some checks failed
Continuous Integration / Update Development (push) Has been cancelled
Some checks failed
Continuous Integration / Update Development (push) Has been cancelled
Reviewed-on: #131
This commit was merged in pull request #131.
This commit is contained in:
20
ui/src/components/tooltip/Tooltip.vue
Normal file
20
ui/src/components/tooltip/Tooltip.vue
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
open: boolean,
|
||||||
|
message: string
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative inline-flex items-center group w-min">
|
||||||
|
<slot></slot>
|
||||||
|
<div v-if="open" class="pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2
|
||||||
|
whitespace-nowrap rounded-md bg-popover px-2 py-1 text-xs
|
||||||
|
text-popover-foreground shadow-md border border-border
|
||||||
|
opacity-0 translate-y-1
|
||||||
|
group-hover:opacity-100 group-hover:translate-y-0
|
||||||
|
transition-opacity transition-transform duration-150">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -25,6 +25,7 @@ import Popover from "@/components/ui/popover/Popover.vue";
|
|||||||
import PopoverTrigger from "@/components/ui/popover/PopoverTrigger.vue";
|
import PopoverTrigger from "@/components/ui/popover/PopoverTrigger.vue";
|
||||||
import PopoverContent from "@/components/ui/popover/PopoverContent.vue";
|
import PopoverContent from "@/components/ui/popover/PopoverContent.vue";
|
||||||
import Combobox from '../ui/combobox/Combobox.vue'
|
import Combobox from '../ui/combobox/Combobox.vue'
|
||||||
|
import Tooltip from '../tooltip/Tooltip.vue'
|
||||||
|
|
||||||
|
|
||||||
const { handleSubmit, resetForm, errors, values, setFieldValue } = useForm({
|
const { handleSubmit, resetForm, errors, values, setFieldValue } = useForm({
|
||||||
@@ -50,7 +51,9 @@ watch(() => values.course_id, (newCourseId, oldCourseId) => {
|
|||||||
if (!oldCourseId) return;
|
if (!oldCourseId) return;
|
||||||
|
|
||||||
values.attendees.forEach((a, index) => {
|
values.attendees.forEach((a, index) => {
|
||||||
|
// @ts-ignore
|
||||||
setFieldValue(`attendees[${index}].passed_bookwork`, false);
|
setFieldValue(`attendees[${index}].passed_bookwork`, false);
|
||||||
|
// @ts-ignore
|
||||||
setFieldValue(`attendees[${index}].passed_qual`, false);
|
setFieldValue(`attendees[${index}].passed_qual`, false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -326,22 +329,13 @@ const filteredMembers = computed(() => {
|
|||||||
<VeeField v-slot="{ field }" :name="`attendees[${index}].passed_bookwork`" type="checkbox"
|
<VeeField v-slot="{ field }" :name="`attendees[${index}].passed_bookwork`" type="checkbox"
|
||||||
:value="false" :unchecked-value="true">
|
:value="false" :unchecked-value="true">
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<div class="relative inline-flex items-center group">
|
<Tooltip :open="!selectedCourse?.hasBookwork"
|
||||||
|
message="This course does not have bookwork">
|
||||||
<Checkbox :disabled="!selectedCourse?.hasBookwork"
|
<Checkbox :disabled="!selectedCourse?.hasBookwork"
|
||||||
:name="`attendees[${index}].passed_bookwork`" :model-value="!field.checked"
|
:name="`attendees[${index}].passed_bookwork`" :model-value="!field.checked"
|
||||||
@update:model-value="field['onUpdate:modelValue']">
|
@update:model-value="field['onUpdate:modelValue']">
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<!-- Tooltip bubble -->
|
</Tooltip>
|
||||||
<div v-if="!selectedCourse?.hasBookwork" class="pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2
|
|
||||||
whitespace-nowrap rounded-md bg-popover px-2 py-1 text-xs
|
|
||||||
text-popover-foreground shadow-md border border-border
|
|
||||||
opacity-0 translate-y-1
|
|
||||||
group-hover:opacity-100 group-hover:translate-y-0
|
|
||||||
transition-opacity transition-transform duration-150">
|
|
||||||
This course does not have bookwork
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="h-4">
|
<div class="h-4">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -351,20 +345,12 @@ const filteredMembers = computed(() => {
|
|||||||
<VeeField v-slot="{ field }" :name="`attendees[${index}].passed_qual`" type="checkbox"
|
<VeeField v-slot="{ field }" :name="`attendees[${index}].passed_qual`" type="checkbox"
|
||||||
:value="false" :unchecked-value="true">
|
:value="false" :unchecked-value="true">
|
||||||
<div class="flex flex-col items-center">
|
<div class="flex flex-col items-center">
|
||||||
<div class="relative inline-flex items-center group">
|
<Tooltip :open="!selectedCourse?.hasQual"
|
||||||
|
message="This course does not have a qualification">
|
||||||
<Checkbox :disabled="!selectedCourse?.hasQual"
|
<Checkbox :disabled="!selectedCourse?.hasQual"
|
||||||
:name="`attendees[${index}].passed_qual`" :model-value="!field.checked"
|
:name="`attendees[${index}].passed_qual`" :model-value="!field.checked"
|
||||||
@update:model-value="field['onUpdate:modelValue']"></Checkbox>
|
@update:model-value="field['onUpdate:modelValue']"></Checkbox>
|
||||||
<!-- Tooltip bubble -->
|
</Tooltip>
|
||||||
<div v-if="!selectedCourse?.hasQual" class="pointer-events-none absolute -top-9 left-1/2 -translate-x-1/2
|
|
||||||
whitespace-nowrap rounded-md bg-popover px-2 py-1 text-xs
|
|
||||||
text-popover-foreground shadow-md border border-border
|
|
||||||
opacity-0 translate-y-1
|
|
||||||
group-hover:opacity-100 group-hover:translate-y-0
|
|
||||||
transition-opacity transition-transform duration-150">
|
|
||||||
This course does not have a qualification
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="h-4">
|
<div class="h-4">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@/components/ui/table'
|
} from '@/components/ui/table'
|
||||||
import { ArrowUpDown, Funnel, Plus, Search, X } from 'lucide-vue-next';
|
import { ArrowUpDown, ChevronDown, ChevronUp, Funnel, Plus, Search, X } from 'lucide-vue-next';
|
||||||
import Button from '@/components/ui/button/Button.vue';
|
import Button from '@/components/ui/button/Button.vue';
|
||||||
import TrainingReportForm from '@/components/trainingReport/trainingReportForm.vue';
|
import TrainingReportForm from '@/components/trainingReport/trainingReportForm.vue';
|
||||||
import Checkbox from '@/components/ui/checkbox/Checkbox.vue';
|
import Checkbox from '@/components/ui/checkbox/Checkbox.vue';
|
||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
PaginationNext,
|
PaginationNext,
|
||||||
PaginationPrevious,
|
PaginationPrevious,
|
||||||
} from '@/components/ui/pagination'
|
} from '@/components/ui/pagination'
|
||||||
|
import Tooltip from '@/components/tooltip/Tooltip.vue';
|
||||||
|
|
||||||
enum sidePanelState { view, create, closed };
|
enum sidePanelState { view, create, closed };
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ watch(() => route.params.id, async (newID) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TRLoaded.value = false;
|
TRLoaded.value = false;
|
||||||
|
expanded.value = null;
|
||||||
viewTrainingReport(Number(route.params.id));
|
viewTrainingReport(Number(route.params.id));
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -126,6 +128,8 @@ function setPage(pagenum: number) {
|
|||||||
pageNum.value = pagenum;
|
pageNum.value = pagenum;
|
||||||
loadTrainingReports();
|
loadTrainingReports();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const expanded = ref<number>(null);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -197,8 +201,8 @@ function setPage(pagenum: number) {
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-5 flex justify-between" :class="sidePanel !== sidePanelState.closed ? 'flex-col items-center' : 'items-center justify-between'"
|
<div class="mt-5 flex justify-between"
|
||||||
>
|
:class="sidePanel !== sidePanelState.closed ? 'flex-col items-center' : 'items-center justify-between'">
|
||||||
<div></div>
|
<div></div>
|
||||||
<Pagination v-slot="{ page }" :items-per-page="pageData?.pageSize || 10" :total="pageData?.total || 10"
|
<Pagination v-slot="{ page }" :items-per-page="pageData?.pageSize || 10" :total="pageData?.total || 10"
|
||||||
:default-page="2" :page="pageNum" @update:page="setPage">
|
:default-page="2" :page="pageNum" @update:page="setPage">
|
||||||
@@ -255,89 +259,180 @@ function setPage(pagenum: number) {
|
|||||||
<!-- Trainers -->
|
<!-- Trainers -->
|
||||||
<div>
|
<div>
|
||||||
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Trainers</label>
|
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Trainers</label>
|
||||||
<div class="grid grid-cols-4 py-2 text-sm font-medium text-muted-foreground border-b">
|
<div
|
||||||
|
class="grid grid-cols-[1fr_1fr_2fr_3rem] py-2 text-sm font-medium text-muted-foreground border-b">
|
||||||
<span>Name</span>
|
<span>Name</span>
|
||||||
<span class="">Role</span>
|
<span class="">Role</span>
|
||||||
<span class="text-right col-span-2">Remarks</span>
|
<span class="text-right">Remarks</span>
|
||||||
|
<span></span>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="person in focusedTrainingTrainers"
|
<div v-for="person in focusedTrainingTrainers" class=" items-center border-b last:border-none"
|
||||||
class="grid grid-cols-4 py-2 items-center border-b last:border-none">
|
:class="expanded === person.attendee_id && 'bg-muted/20'">
|
||||||
|
<div class="grid grid-cols-[1fr_1fr_2fr_3rem] items-center py-2">
|
||||||
<div>
|
<div>
|
||||||
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
||||||
class="justify-self-start"></MemberCard>
|
class="justify-self-start"></MemberCard>
|
||||||
<p v-else>{{ person.attendee_name }}</p>
|
<p v-else>{{ person.attendee_name }}</p>
|
||||||
</div>
|
</div>
|
||||||
<p class="">{{ person.role.name }}</p>
|
<p class="">{{ person.role.name }}</p>
|
||||||
<p class="col-span-2 text-right px-2"
|
<p class="text-right px-2 truncate"
|
||||||
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
|
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
|
||||||
{{ person.remarks == "" ?
|
{{ person.remarks == "" ?
|
||||||
'--'
|
'--'
|
||||||
: person.remarks }}</p>
|
: person.remarks }}</p>
|
||||||
|
<div class="w-min mx-auto">
|
||||||
|
<Button v-if="expanded === person.attendee_id" @click.stop="expanded = null"
|
||||||
|
variant="ghost" size="icon">
|
||||||
|
<ChevronUp class="size-6" />
|
||||||
|
</Button>
|
||||||
|
<Button v-else @click.stop="expanded = person.attendee_id" variant="ghost"
|
||||||
|
size="icon">
|
||||||
|
<ChevronDown class="size-6" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-full" v-if="expanded === person.attendee_id">
|
||||||
|
<div class="px-6 pb-5 pt-2 space-y-2">
|
||||||
|
<p class="text-sm font-medium text-foreground">
|
||||||
|
Remarks
|
||||||
|
</p>
|
||||||
|
<p v-if="person.remarks"
|
||||||
|
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
|
||||||
|
{{ person.remarks }}
|
||||||
|
</p>
|
||||||
|
<p v-else class="text-sm text-muted-foreground italic">
|
||||||
|
None provided
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- trainees -->
|
<!-- trainees -->
|
||||||
<div>
|
<div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Trainees</label>
|
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Trainees</label>
|
||||||
<div class="grid grid-cols-5 py-2 text-sm font-medium text-muted-foreground border-b">
|
<div
|
||||||
|
class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 text-sm font-medium text-muted-foreground border-b px-2">
|
||||||
<span>Name</span>
|
<span>Name</span>
|
||||||
<span class="">Bookwork</span>
|
<span class="text-center">Bookwork</span>
|
||||||
<span class="">Qual</span>
|
<span class="text-center">Qual</span>
|
||||||
<span class="text-right col-span-2">Remarks</span>
|
<span class="text-right">Remarks</span>
|
||||||
|
<span class="w-15"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="person in focusedTrainingTrainees"
|
<div v-for="person in focusedTrainingTrainees" class="border-b last:border-none"
|
||||||
class="grid grid-cols-5 py-2 items-center border-b last:border-none">
|
:class="expanded === person.attendee_id && 'bg-muted/20'">
|
||||||
|
<div class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 items-center mx-2">
|
||||||
<div>
|
<div>
|
||||||
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
||||||
class="justify-self-start"></MemberCard>
|
class="justify-self-start"></MemberCard>
|
||||||
<p v-else>{{ person.attendee_name }}</p>
|
<p v-else>{{ person.attendee_name }}</p>
|
||||||
</div>
|
</div>
|
||||||
<Checkbox :disabled="!focusedTrainingReport.course.hasQual"
|
<Tooltip :open="!focusedTrainingReport.course.hasBookwork" class="mx-auto"
|
||||||
:model-value="person.passed_bookwork" class="pointer-events-none ml-5">
|
message="This course does not have bookwork">
|
||||||
|
<Checkbox :disabled="!focusedTrainingReport.course.hasBookwork"
|
||||||
|
:model-value="person.passed_bookwork" class="pointer-events-none">
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip :open="!focusedTrainingReport.course.hasQual" class="mx-auto"
|
||||||
|
message="This course does not have a qualification">
|
||||||
<Checkbox :disabled="!focusedTrainingReport.course.hasQual"
|
<Checkbox :disabled="!focusedTrainingReport.course.hasQual"
|
||||||
:model-value="person.passed_qual" class="pointer-events-none ml-1">
|
:model-value="person.passed_qual" class="pointer-events-none ml-1">
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<p class="col-span-2 text-right px-2"
|
</Tooltip>
|
||||||
|
<p class="text-right truncate"
|
||||||
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
|
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
|
||||||
{{ person.remarks == "" ?
|
{{ person.remarks == "" ?
|
||||||
'--'
|
'--'
|
||||||
: person.remarks }}</p>
|
: person.remarks }}</p>
|
||||||
|
<div class="w-min mx-auto">
|
||||||
|
<Button v-if="expanded === person.attendee_id" @click.stop="expanded = null"
|
||||||
|
variant="ghost" size="icon">
|
||||||
|
<ChevronUp class="size-6" />
|
||||||
|
</Button>
|
||||||
|
<Button v-else @click.stop="expanded = person.attendee_id" variant="ghost"
|
||||||
|
size="icon">
|
||||||
|
<ChevronDown class="size-6" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-span-full" v-if="expanded === person.attendee_id">
|
||||||
|
<div class="px-6 pb-5 pt-2 space-y-2">
|
||||||
|
<p class="text-sm font-medium text-foreground">
|
||||||
|
Remarks
|
||||||
|
</p>
|
||||||
|
<p v-if="person.remarks"
|
||||||
|
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
|
||||||
|
{{ person.remarks }}
|
||||||
|
</p>
|
||||||
|
<p v-else class="text-sm text-muted-foreground italic">
|
||||||
|
None provided
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- No Shows -->
|
<!-- No Shows -->
|
||||||
<div v-if="focusedNoShows.length != 0">
|
<div v-if="focusedNoShows.length != 0">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<label class="scroll-m-20 text-xl font-semibold tracking-tight">No Shows</label>
|
<label class="scroll-m-20 text-xl font-semibold tracking-tight">
|
||||||
<div class="grid grid-cols-5 py-2 text-sm font-medium text-muted-foreground border-b">
|
No Shows
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 text-sm font-medium text-muted-foreground border-b">
|
||||||
<span>Name</span>
|
<span>Name</span>
|
||||||
<!-- <span class="">Role</span>
|
<span></span>
|
||||||
<span class="">Role</span> -->
|
<span></span>
|
||||||
<div></div>
|
<span class="text-right">Remarks</span>
|
||||||
<div></div>
|
<span></span>
|
||||||
<span class="text-right col-span-2">Remarks</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="person in focusedNoShows"
|
|
||||||
class="grid grid-cols-5 py-2 items-center border-b last:border-none">
|
<div v-for="person in focusedNoShows" :key="person.attendee_id ?? person.attendee_name"
|
||||||
|
class="border-b last:border-none transition-colors"
|
||||||
|
:class="expanded === person.attendee_id && 'bg-muted/20'">
|
||||||
|
<!-- Row -->
|
||||||
|
<div class="grid grid-cols-[1fr_5rem_5rem_2fr_3rem] py-2 items-center">
|
||||||
|
<!-- Name -->
|
||||||
<div>
|
<div>
|
||||||
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id"
|
<MemberCard v-if="person.attendee_id" :member-id="person.attendee_id" />
|
||||||
class="justify-self-start"></MemberCard>
|
|
||||||
<p v-else>{{ person.attendee_name }}</p>
|
<p v-else>{{ person.attendee_name }}</p>
|
||||||
</div>
|
</div>
|
||||||
<!-- <Checkbox :default-value="person.passed_bookwork ? true : false" class="pointer-events-none">
|
|
||||||
</Checkbox>
|
|
||||||
<Checkbox :default-value="person.passed_qual ? true : false" class="pointer-events-none">
|
|
||||||
</Checkbox> -->
|
|
||||||
<div></div>
|
<div></div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<p class="col-span-2 text-right px-2"
|
|
||||||
:class="person.remarks == '' ? 'text-muted-foreground' : ''">
|
<p class="text-right px-2 truncate" :class="!person.remarks && 'text-muted-foreground'">
|
||||||
{{ person.remarks == "" ?
|
{{ person.remarks || '--' }}
|
||||||
'--'
|
</p>
|
||||||
: person.remarks }}</p>
|
|
||||||
|
<Button variant="ghost" size="icon" @click.stop="expanded === person.attendee_id
|
||||||
|
? expanded = null
|
||||||
|
: expanded = person.attendee_id">
|
||||||
|
<ChevronDown v-if="expanded !== person.attendee_id" class="size-5" />
|
||||||
|
<ChevronUp v-else class="size-5" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="expanded === person.attendee_id" class="col-span-full">
|
||||||
|
<div class="px-6 py-4 space-y-2">
|
||||||
|
<p class="text-sm font-medium text-foreground">
|
||||||
|
Remarks
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p v-if="person.remarks"
|
||||||
|
class="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap max-h-72 overflow-y-auto">
|
||||||
|
{{ person.remarks }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p v-else class="text-sm text-muted-foreground italic">
|
||||||
|
None provided
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Remarks</label>
|
<label class="scroll-m-20 text-xl font-semibold tracking-tight">Remarks</label>
|
||||||
@@ -368,33 +463,3 @@ function setPage(pagenum: number) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* Firefox */
|
|
||||||
.scrollbar-themed {
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #555 #1f1f1f;
|
|
||||||
padding-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Chrome, Edge, Safari */
|
|
||||||
.scrollbar-themed::-webkit-scrollbar {
|
|
||||||
width: 10px;
|
|
||||||
/* slightly wider to allow padding look */
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollbar-themed::-webkit-scrollbar-track {
|
|
||||||
background: #1f1f1f;
|
|
||||||
margin-left: 6px;
|
|
||||||
/* ❗ adds space between content + scrollbar */
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollbar-themed::-webkit-scrollbar-thumb {
|
|
||||||
background: #555;
|
|
||||||
border-radius: 9999px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scrollbar-themed::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #777;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user