feat: mobile responsive
This commit is contained in:
@@ -55,7 +55,7 @@ const communications = createListResource({
|
||||
cache: ['batch', props.batch],
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
<style scoped>
|
||||
.prose-sm p {
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
<div class="flex flex-col overflow-y-auto">
|
||||
<SidebarLink
|
||||
v-for="link in links"
|
||||
:icon="link.icon"
|
||||
:label="link.label"
|
||||
:to="link.to"
|
||||
:activeFor="link.activeFor"
|
||||
:link="link"
|
||||
:isCollapsed="isSidebarCollapsed"
|
||||
class="mx-2 my-0.5"
|
||||
/>
|
||||
|
||||
@@ -61,7 +61,7 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
<style scoped>
|
||||
.short-introduction {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
:class="{ 'default-image': !course.image }"
|
||||
:style="{ backgroundImage: 'url(' + encodeURI(course.image) + ')' }"
|
||||
>
|
||||
<div class="flex relative top-4 left-4 w-fit">
|
||||
<Badge theme="gray" size="lg" class="mr-2" v-for="tag in course.tags">
|
||||
<div class="flex relative top-4 left-4 w-fit flex-wrap">
|
||||
<Badge theme="gray" size="md" class="mr-2" v-for="tag in course.tags">
|
||||
{{ tag }}
|
||||
</Badge>
|
||||
</div>
|
||||
@@ -127,7 +127,7 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<style>
|
||||
<style scoped>
|
||||
.course-image {
|
||||
height: 168px;
|
||||
width: 100%;
|
||||
|
||||
@@ -158,7 +158,7 @@ const getCurrentChapter = () => {
|
||||
return currentChapter.value
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
<style scoped>
|
||||
.outline-lesson:has(.router-link-active) {
|
||||
background-color: theme('colors.gray.100');
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<template>
|
||||
<div class="relative flex h-full flex-col">
|
||||
<div class="h-full flex-1">
|
||||
<div class="flex h-full">
|
||||
<div class="relative block min-h-0 flex-shrink-0 overflow-hidden hover:overflow-auto">
|
||||
<slot name="sidebar" />
|
||||
<AppSidebar />
|
||||
</div>
|
||||
<div class="w-full overflow-auto" id="scrollContainer">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative flex h-full flex-col">
|
||||
<div class="h-full flex-1">
|
||||
<div class="flex h-screen text-base">
|
||||
<div
|
||||
class="relative block min-h-0 flex-shrink-0 overflow-hidden hover:overflow-auto"
|
||||
>
|
||||
<slot name="sidebar" />
|
||||
<AppSidebar />
|
||||
</div>
|
||||
<div class="w-full overflow-auto" id="scrollContainer">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import AppSidebar from './AppSidebar.vue'
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
<div class="flex items-center my-4">
|
||||
<Badge :label="job.type" theme="green" size="lg" class="mr-4" />
|
||||
<Badge :label="job.location" theme="gray" size="lg">
|
||||
<Badge :label="job.location.split(' ')[0]" theme="gray" size="lg">
|
||||
<template #prefix>
|
||||
<MapPin class="h-4 w-4 stroke-1.5" />
|
||||
</template>
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
<template>
|
||||
<div class="flex h-full flex-col">
|
||||
<div class="h-full overflow-auto" id="scrollContainer">
|
||||
<div class="h-full" id="scrollContainer">
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
v-if="tabs"
|
||||
class="grid grid-cols-5 border-t border-gray-300 standalone:pb-4"
|
||||
:style="{ gridTemplateColumns: `repeat(${tabs.length}, minmax(0, 1fr))` }"
|
||||
class="grid grid-cols-5 border-t border-gray-300 sticky bottom-0 z-10 bg-white standalone:pb-4"
|
||||
:style="{
|
||||
gridTemplateColumns: `repeat(${tabs.length - 1}, minmax(0, 1fr))`,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.label"
|
||||
:class="isVisible(tab) ? 'block' : 'hidden'"
|
||||
class="flex flex-col items-center justify-center py-3 transition active:scale-95"
|
||||
@click="handleClick(tab)"
|
||||
>
|
||||
<component :is="tab.icon" class="h-6 w-6 stroke-1.5 text-gray-700" />
|
||||
<component
|
||||
:is="tab.icon"
|
||||
class="h-7 w-7 stroke-1.5"
|
||||
:class="[isActive(tab) ? 'text-gray-900' : 'text-gray-600']"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -22,19 +29,33 @@
|
||||
<script setup>
|
||||
import { getSidebarLinks } from '../utils'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
import { computed, inject } from 'vue'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
|
||||
const { logout, user } = sessionStore()
|
||||
let { isLoggedIn } = sessionStore()
|
||||
|
||||
const router = useRouter()
|
||||
const tabs = computed(() => {
|
||||
return getSidebarLinks()
|
||||
})
|
||||
|
||||
/* let isActive = computed((tab) => {
|
||||
console.log(tab);
|
||||
return router.currentRoute.value.name === tab.to
|
||||
}) */
|
||||
let isActive = (tab) => {
|
||||
return tab.activeFor?.includes(router.currentRoute.value.name)
|
||||
}
|
||||
|
||||
const handleClick = (tab) => {
|
||||
router.push({ name: tab.to })
|
||||
if (tab.label == 'Log in') window.location.href = '/login'
|
||||
else if (tab.label == 'Log out')
|
||||
logout.submit().then(() => {
|
||||
isLoggedIn = false
|
||||
})
|
||||
else router.push({ name: tab.to })
|
||||
}
|
||||
|
||||
const isVisible = (tab) => {
|
||||
if (tab.label == 'Log in') return !isLoggedIn
|
||||
else if (tab.label == 'Log out') return isLoggedIn
|
||||
else return true
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<button
|
||||
v-if="link && !link.onlyMobile"
|
||||
class="flex h-7 cursor-pointer items-center rounded text-gray-800 duration-300 ease-in-out focus:outline-none focus:transition-none focus-visible:rounded focus-visible:ring-2 focus-visible:ring-gray-400"
|
||||
:class="isActive ? 'bg-white shadow-sm' : 'hover:bg-gray-100'"
|
||||
@click="handleClick"
|
||||
@@ -8,10 +9,13 @@
|
||||
class="flex items-center duration-300 ease-in-out"
|
||||
:class="isCollapsed ? 'p-1' : 'px-2 py-1'"
|
||||
>
|
||||
<Tooltip :text="label" placement="right">
|
||||
<Tooltip :text="link.label" placement="right">
|
||||
<slot name="icon">
|
||||
<span class="grid h-5 w-6 flex-shrink-0 place-items-center">
|
||||
<component :is="icon" class="h-5 w-5 stroke-1.5 text-gray-800" />
|
||||
<component
|
||||
:is="link.icon"
|
||||
class="h-5 w-5 stroke-1.5 text-gray-800"
|
||||
/>
|
||||
</span>
|
||||
</slot>
|
||||
</Tooltip>
|
||||
@@ -23,7 +27,7 @@
|
||||
: 'ml-2 w-auto opacity-100'
|
||||
"
|
||||
>
|
||||
{{ label }}
|
||||
{{ link.label }}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
@@ -37,20 +41,9 @@ import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
icon: {
|
||||
type: Function,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
to: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
activeFor: {
|
||||
type: Array,
|
||||
default: [],
|
||||
link: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isCollapsed: {
|
||||
type: Boolean,
|
||||
@@ -59,10 +52,10 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
router.push({ name: props.to })
|
||||
router.push({ name: props.link.to })
|
||||
}
|
||||
|
||||
let isActive = computed(() => {
|
||||
return props.activeFor.includes(router.currentRoute.value.name)
|
||||
return props.link?.activeFor?.includes(router.currentRoute.value.name)
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user