mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 06:29:30 -07:00
small cleanup
This commit is contained in:
@@ -17,7 +17,8 @@
|
|||||||
<Accordion expandIcon="pi pi-chevron-right" collapseIcon="pi pi-chevron-down">
|
<Accordion expandIcon="pi pi-chevron-right" collapseIcon="pi pi-chevron-down">
|
||||||
<AccordionPanel value="setup">
|
<AccordionPanel value="setup">
|
||||||
<AccordionHeader>Setup Steps</AccordionHeader>
|
<AccordionHeader>Setup Steps</AccordionHeader>
|
||||||
<AccordionContent>
|
<AccordionContent
|
||||||
|
:pt="{ transition: { enterFromClass: '', enterActiveClass: '', enterToClass: '', leaveFromClass: '', leaveActiveClass: '', leaveToClass: '' } }">
|
||||||
<div class="setup-content">
|
<div class="setup-content">
|
||||||
<p class="demo-extra-info">1. Initialize a config file for your project</p>
|
<p class="demo-extra-info">1. Initialize a config file for your project</p>
|
||||||
|
|
||||||
@@ -78,15 +79,32 @@ const { command } = defineProps<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.code-block {
|
.code-block {
|
||||||
border-radius: 8px;
|
border-radius: 15px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid #142216;
|
border: 1px solid #142216;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.p-accordionpanel) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.p-accordion-header) {
|
:deep(.p-accordion-header) {
|
||||||
background: #0b0b0b;
|
background: #0b0b0b !important;
|
||||||
border: 1px solid #142216;
|
border: 1px solid #142216 !important;
|
||||||
border-radius: 20px;
|
border-radius: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.p-accordionpanel:not(.p-disabled).p-accordionpanel-active > .p-accordionheader) {
|
||||||
|
background: #0b0b0b !important;
|
||||||
|
border: 1px solid #142216 !important;
|
||||||
|
border-radius: 15px 15px 0 0;
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.p-accordionpanel:not(.p-disabled) > .p-accordionheader) {
|
||||||
|
border: 1px solid #142216 !important;
|
||||||
|
border-radius: 15px;
|
||||||
|
background: #0b0b0b !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.p-accordionpanel) {
|
:deep(.p-accordionpanel) {
|
||||||
@@ -109,27 +127,26 @@ const { command } = defineProps<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.p-accordion-content) {
|
:deep(.p-accordion-content) {
|
||||||
background: #0b0b0b;
|
background: #0b0b0b !important;
|
||||||
border: 1px solid #142216;
|
border: 1px solid #142216 !important;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
border-radius: 0 0 20px 20px;
|
border-radius: 0 0 15px 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.p-accordioncontent-content) {
|
||||||
|
background: #0b0b0b !important;
|
||||||
|
border: 1px solid #142216 !important;
|
||||||
|
border-radius: 0 0 15px 15px;
|
||||||
|
border-top: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code Block Styles */
|
||||||
:deep(.v-code-block) {
|
:deep(.v-code-block) {
|
||||||
background: #0b0b0b;
|
background: #0b0b0b;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.v-code-block--tab-highlightjs-github-dark-icon) {
|
|
||||||
color: #999 !important;
|
|
||||||
fill: #999 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.v-code-block--me-1) {
|
|
||||||
margin-right: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.v-code-block pre) {
|
:deep(.v-code-block pre) {
|
||||||
background: #0b0b0b;
|
background: #0b0b0b;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -141,4 +158,13 @@ const { command } = defineProps<{
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.v-code-block--tab-highlightjs-github-dark-icon) {
|
||||||
|
color: #999 !important;
|
||||||
|
fill: #999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.v-code-block--me-1) {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,10 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="code-example">
|
<div class="code-example">
|
||||||
<div v-for="[name, snippet] in codeEntries" :key="name" class="code-section">
|
<div v-for="[name, snippet] in codeEntries" :key="name" class="code-section">
|
||||||
<h2 v-if="shouldShowTitle()" class="demo-title">{{ getDisplayName(name) }}</h2>
|
<h2 class="demo-title">{{ getDisplayName(name) }}</h2>
|
||||||
|
|
||||||
<VCodeBlock v-if="snippet" :code="snippet" highlightjs :lang="getLanguage(name)" theme="nord"
|
<div v-if="snippet" class="code-container">
|
||||||
:copy-button="true" :persistent-copy-button="true" class="code-block" />
|
<div class="code-wrapper" :class="{ 'collapsed': shouldCollapse(snippet) && !isExpanded(name) }">
|
||||||
|
<VCodeBlock :code="snippet" highlightjs :lang="getLanguage(name)" theme="nord" :copy-button="true"
|
||||||
|
:persistent-copy-button="true" class="code-block" />
|
||||||
|
|
||||||
|
<div v-if="shouldCollapse(snippet) && !isExpanded(name)" class="fade-overlay" />
|
||||||
|
|
||||||
|
<button v-if="shouldCollapse(snippet)" class="expand-button" :class="{ 'expanded': isExpanded(name) }"
|
||||||
|
@click="toggleExpanded(name)">
|
||||||
|
{{ isExpanded(name) ? 'Collapse Snippet' : 'See Full Snippet' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="!snippet" class="no-code">
|
<div v-if="!snippet" class="no-code">
|
||||||
<span>Nothing here yet!</span>
|
<span>Nothing here yet!</span>
|
||||||
@@ -15,7 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { VCodeBlock } from '@wdns/vue-code-block'
|
import { VCodeBlock } from '@wdns/vue-code-block'
|
||||||
import type { CodeObject } from '../../types/code'
|
import type { CodeObject } from '../../types/code'
|
||||||
|
|
||||||
@@ -27,12 +38,28 @@ const skipKeys = [
|
|||||||
'cli'
|
'cli'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const expandedSections = ref<Set<string>>(new Set())
|
||||||
|
|
||||||
const codeEntries = computed(() => {
|
const codeEntries = computed(() => {
|
||||||
return Object.entries(props.codeObject).filter(([name]) => !skipKeys.includes(name))
|
return Object.entries(props.codeObject).filter(([name]) => !skipKeys.includes(name))
|
||||||
})
|
})
|
||||||
|
|
||||||
const shouldShowTitle = () => {
|
|
||||||
return true // Show titles for all sections
|
const shouldCollapse = (snippet: string) => {
|
||||||
|
const codeLines = snippet?.split('\n').length || 0
|
||||||
|
return codeLines > 35
|
||||||
|
}
|
||||||
|
|
||||||
|
const isExpanded = (name: string) => {
|
||||||
|
return expandedSections.value.has(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleExpanded = (name: string) => {
|
||||||
|
if (expandedSections.value.has(name)) {
|
||||||
|
expandedSections.value.delete(name)
|
||||||
|
} else {
|
||||||
|
expandedSections.value.add(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDisplayName = (name: string) => {
|
const getDisplayName = (name: string) => {
|
||||||
@@ -62,12 +89,64 @@ const getLanguage = (name: string) => {
|
|||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-block {
|
.code-container {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-wrapper {
|
||||||
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid #142216;
|
border: 1px solid #142216;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.code-wrapper.collapsed {
|
||||||
|
max-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block {
|
||||||
|
overflow: hidden;
|
||||||
|
border: none;
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-overlay {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 60%;
|
||||||
|
background: linear-gradient(to bottom, transparent, #0b0b0b);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.75rem;
|
||||||
|
right: 0.75rem;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
height: 2.5rem;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
background-color: #0b0b0b;
|
||||||
|
border: 1px solid #142216;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 2;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-button:hover {
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-button:active {
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
.no-code {
|
.no-code {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -82,7 +161,7 @@ const getLanguage = (name: string) => {
|
|||||||
|
|
||||||
:deep(.v-code-block) {
|
:deep(.v-code-block) {
|
||||||
background: #0b0b0b;
|
background: #0b0b0b;
|
||||||
border-radius: 10px;
|
border-radius: 15px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
66
src/components/common/BackToTopButton.vue
Normal file
66
src/components/common/BackToTopButton.vue
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<Button :style="{
|
||||||
|
fontWeight: 500,
|
||||||
|
borderRadius: '0.75rem',
|
||||||
|
border: '1px solid #142216',
|
||||||
|
padding: '1rem',
|
||||||
|
position: 'fixed',
|
||||||
|
right: '2.3em',
|
||||||
|
zIndex: 98,
|
||||||
|
boxShadow: '10px 0 25px rgba(0, 0, 0, 0.2)',
|
||||||
|
transition: '0.3s ease',
|
||||||
|
opacity: visible ? 1 : 0,
|
||||||
|
bottom: visible ? '2.5em' : '1em',
|
||||||
|
cursor: visible ? 'pointer' : 'default'
|
||||||
|
}" class="back-to-top" @click="visible && scrollToTop()">
|
||||||
|
<i class="pi pi-arrow-up" style="color: #fff; font-size: 1rem;"></i>
|
||||||
|
</Button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted } from 'vue'
|
||||||
|
import { useToast } from 'primevue/usetoast'
|
||||||
|
import Button from 'primevue/button'
|
||||||
|
|
||||||
|
const toast = useToast()
|
||||||
|
const visible = ref(false)
|
||||||
|
|
||||||
|
const messages = [
|
||||||
|
'🐴 Country roads, take me home!',
|
||||||
|
'🚀 To infinity and beyond!',
|
||||||
|
'🦾 Get to the choppa!',
|
||||||
|
'🚕 Grove Street, home...',
|
||||||
|
'🐉 Fus Ro Dah!',
|
||||||
|
'🍄 The princess is in another castle!',
|
||||||
|
'🦸♂️ Avengers, assemble!',
|
||||||
|
'🗡️ It\'s dangerous to go alone! Take this.',
|
||||||
|
'📜 A wizard is never late.',
|
||||||
|
'💍 Foul Tarnished, in search of the Elden Ring!',
|
||||||
|
'🐊 See you later, alligator.',
|
||||||
|
'🔥 Dracarys!'
|
||||||
|
]
|
||||||
|
|
||||||
|
const getRandomMessage = (messages: string[]) =>
|
||||||
|
messages[Math.floor(Math.random() * messages.length)]
|
||||||
|
|
||||||
|
const scrollToTop = () => {
|
||||||
|
window.scrollTo(0, 0)
|
||||||
|
toast.add({
|
||||||
|
severity: 'secondary',
|
||||||
|
summary: getRandomMessage(messages),
|
||||||
|
life: 3000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onScroll = () => {
|
||||||
|
visible.value = window.scrollY > 500
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('scroll', onScroll)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('scroll', onScroll)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -8,11 +8,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<Toast position="bottom-right"
|
<Toast position="bottom-right"
|
||||||
:closeButtonProps="{ style: { justifyContent: 'flex-end', right: '0', margin: '0', outline: 'none', border: 'none' } }"
|
:closeButtonProps="{ style: { right: '0', margin: '0', outline: 'none', border: 'none' } }"
|
||||||
:pt="{
|
:pt="{
|
||||||
message: {
|
message: {
|
||||||
style: {
|
style: {
|
||||||
borderRadius: '10px'
|
borderRadius: '10px',
|
||||||
|
border: '1px solid #142216',
|
||||||
|
backgroundColor: '#0b0b0b',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
messageContent: {
|
messageContent: {
|
||||||
|
|||||||
@@ -4,30 +4,6 @@
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.landing-wrapper::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 300px;
|
|
||||||
height: 100vh;
|
|
||||||
background: linear-gradient(to right, #0b0b0b, transparent);
|
|
||||||
z-index: 2;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landing-wrapper::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
width: 300px;
|
|
||||||
height: 100vh;
|
|
||||||
background: linear-gradient(to left, #0b0b0b, transparent);
|
|
||||||
z-index: 2;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landing-content {
|
.landing-content {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -13,57 +13,58 @@
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- TODO: Add BackToTopButton component when available -->
|
<BackToTopButton />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch, onMounted, nextTick, defineAsyncComponent } from 'vue'
|
import { ref, computed, watch, onMounted, nextTick, defineAsyncComponent } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { componentMap } from '../constants/Components'
|
import { componentMap } from '../constants/Components'
|
||||||
import { decodeLabel } from '../utils/utils'
|
import { decodeLabel } from '../utils/utils'
|
||||||
import '../css/category.css'
|
import BackToTopButton from '@/components/common/BackToTopButton.vue'
|
||||||
|
import '../css/category.css'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const scrollRef = ref<HTMLDivElement | null>(null)
|
const scrollRef = ref<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
const subcategory = computed(() => route.params.subcategory as string)
|
const subcategory = computed(() => route.params.subcategory as string)
|
||||||
const decodedLabel = computed(() => decodeLabel(subcategory.value))
|
const decodedLabel = computed(() => decodeLabel(subcategory.value))
|
||||||
|
|
||||||
// Lazy load the component based on subcategory
|
// Lazy load the component based on subcategory
|
||||||
const SubcategoryComponent = computed(() => {
|
const SubcategoryComponent = computed(() => {
|
||||||
if (!subcategory.value) {
|
if (!subcategory.value) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const componentLoader = componentMap[subcategory.value as keyof typeof componentMap]
|
const componentLoader = componentMap[subcategory.value as keyof typeof componentMap]
|
||||||
|
|
||||||
if (!componentLoader) {
|
if (!componentLoader) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return defineAsyncComponent(componentLoader)
|
return defineAsyncComponent(componentLoader)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Update document title
|
// Update document title
|
||||||
watch(decodedLabel, (newLabel) => {
|
watch(decodedLabel, (newLabel) => {
|
||||||
if (newLabel) {
|
if (newLabel) {
|
||||||
document.title = `Vue Bits - ${newLabel}`
|
document.title = `Vue Bits - ${newLabel}`
|
||||||
}
|
}
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
// Scroll to top when subcategory changes
|
// Scroll to top when subcategory changes
|
||||||
watch(subcategory, async () => {
|
watch(subcategory, async () => {
|
||||||
if (scrollRef.value) {
|
if (scrollRef.value) {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
scrollRef.value.scrollTo(0, 0)
|
scrollRef.value.scrollTo(0, 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// Initial scroll to top
|
// Initial scroll to top
|
||||||
if (scrollRef.value) {
|
if (scrollRef.value) {
|
||||||
scrollRef.value.scrollTo(0, 0)
|
scrollRef.value.scrollTo(0, 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user