| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- <script setup lang="ts">
- import SimpleScrollView from '../display/SimpleScrollView.vue';
- import { ref, watch, type PropType } from 'vue';
- export interface CatalogItem {
- title: string,
- level: number,
- scrollPos: number,
- anchor: string,
- }
- const emit = defineEmits([
- "goToItem"
- ])
- const props = defineProps({
- items: {
- type: Object as PropType<CatalogItem[]>,
- default: () => []
- },
- scrollContainer: {
- type: Object as PropType<HTMLElement|null>,
- default: () => null,
- },
- })
- const activeIndex = ref(-1);
- function handlerContainerScroll(e: Event) {
- const container = e.target as HTMLElement;
- const scrollTop = container.scrollTop;
- activeIndex.value = 0;
- for (let i = props.items.length - 1; i >= 0; i--) {
- const item = props.items[i];
- if (scrollTop >= item.scrollPos) {
- activeIndex.value = i;
- break;
- }
- }
- }
- function handlerItemClick(item: CatalogItem) {
- if (item.anchor) {
- const el = document.getElementById(item.anchor);
- if (el) {
- el.scrollIntoView({ behavior: 'smooth' });
- }
- }
- emit('goToItem', item);
- }
- watch(() => props.scrollContainer, (newVal, oldVal) => {
- if (oldVal && oldVal instanceof HTMLElement)
- oldVal.removeEventListener('scroll', handlerContainerScroll);
- if (newVal && newVal instanceof HTMLElement)
- newVal.addEventListener('scroll', handlerContainerScroll);
- }, { immediate: true });
- </script>
- <template>
- <SimpleScrollView class="nana-catalog" :scrollY="true">
- <div>
- <div
- v-for="(item, index) in props.items"
- :key="index"
- :class="[
- 'nana-catalog-item',
- `level-${item.level}`,
- activeIndex === index ? 'active' : '',
- ]"
- @click="handlerItemClick(item)"
- >
- {{ item.title }}
- </div>
- </div>
- </SimpleScrollView>
- </template>
- <style lang="scss">
- .nana-catalog {
- position: relative;
- margin-left: 0.5rem;
- > div {
- display: flex;
- flex-direction: column;
- }
- &::before {
- content: '';
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- width: 1px;
- background-color: var(--nana-text-6);
- }
- .nana-catalog-item {
- position: relative;
- padding: 0.4rem 0.8rem;
- font-size: 1rem;
- color: var(--nana-text-6);
- user-select: none;
- cursor: pointer;
- &.active {
- font-weight: bold;
- color: var(--nana-text-1);
- &::after {
- content: '';
- position: absolute;
- top: calc(50% - 6px);
- left: 0;
- border: 8px solid transparent;
- border-left: 8px solid var(--nana-text-1);
- }
- }
- &.level-1 {
- font-size: 1.2rem;
- padding-left: 1rem;
- }
- &.level-3,
- &.level-4,
- &.level-5 {
- font-size: 0.8rem;
- padding-left: 1.2rem;
-
- &::before {
- content: '·';
- display: inline-block;
- padding-right: 0.6rem;
- }
- }
- &.level-6 {
- font-size: 0.7rem;
- padding-left: 1.6rem;
- }
- }
- }
- </style>
|