✨ (stacked notes) implements overlay
This commit is contained in:
@@ -1,22 +1,35 @@
|
||||
<template>
|
||||
<div class="stacked-note" v-html="content"></div>
|
||||
<div
|
||||
class="stacked-note"
|
||||
:class="{ [className]: true, overlay: displayNoteOverlay }"
|
||||
>
|
||||
<div class="title-stacked-note" :class="titleClassName">{{ title }}</div>
|
||||
<section v-html="content"></section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, nextTick, watch } from 'vue'
|
||||
import { computed, defineComponent, nextTick, watch } from 'vue'
|
||||
import { useFile } from '@/hooks/useFile.hook'
|
||||
import { useLinks } from '@/hooks/useLinks.hook'
|
||||
import { useNoteOverlay } from '@/hooks/useNoteOverlay.hook'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'StackedNote',
|
||||
props: {
|
||||
index: { type: Number, required: true },
|
||||
user: { type: String, required: true },
|
||||
repo: { type: String, required: true },
|
||||
title: { type: String, required: true },
|
||||
sha: { type: String, required: true }
|
||||
},
|
||||
setup(props) {
|
||||
const { content } = useFile(props.user, props.repo, props.sha)
|
||||
const { listenToClick } = useLinks('stacked-note', props.sha)
|
||||
const className = computed(() => `stacked-note-${props.index}`)
|
||||
const titleClassName = computed(() => `title-${className.value}`)
|
||||
|
||||
const { displayNoteOverlay } = useNoteOverlay(className.value, props.index)
|
||||
|
||||
watch(content, () => {
|
||||
if (content.value) {
|
||||
@@ -26,24 +39,43 @@ export default defineComponent({
|
||||
}
|
||||
})
|
||||
|
||||
return { content }
|
||||
return { content, titleClassName, className, displayNoteOverlay }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$border-color: rgba(18, 19, 58, 0.2);
|
||||
|
||||
.stacked-note {
|
||||
text-align: left;
|
||||
border-top: 1px solid rgba(18, 19, 58, 0.2);
|
||||
padding: 0 1rem;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
padding: 1rem 3rem;
|
||||
|
||||
transition: cubic-bezier(0.39, 0.575, 0.565, 1) 0.3s;
|
||||
|
||||
&.overlay {
|
||||
box-shadow: -3px 0 0.4em $border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.title-stacked-note {
|
||||
position: absolute;
|
||||
transform-origin: 0 0;
|
||||
transform: rotate(90deg);
|
||||
top: 1rem;
|
||||
left: 1.5rem;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.title-stacked-note {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.stacked-note {
|
||||
border-top: 0;
|
||||
border-left: 1px solid rgba(18, 19, 58, 0.2);
|
||||
border-left: 1px solid $border-color;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Ref, ref } from '@vue/reactivity'
|
||||
import { nextTick, onUnmounted, watch } from '@vue/runtime-core'
|
||||
import { computed, nextTick, onUnmounted, watch } from '@vue/runtime-core'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { noteEventBus } from '@/bus/noteBusEvent'
|
||||
@@ -26,6 +26,19 @@ export const useNote = (user: Ref<string>, repo: Ref<string>) => {
|
||||
|
||||
const { readme, notFound, tree } = useRepo(user, repo)
|
||||
const { listenToClick } = useLinks('note-display')
|
||||
const titles = computed(() => {
|
||||
return stackedNotes.value.reduce((obj: Record<string, string>, note) => {
|
||||
if (!note) {
|
||||
return obj
|
||||
}
|
||||
const filePath = tree.value.find((file) => file.sha === note)?.path ?? ''
|
||||
const fileNames = filePath.split('.')
|
||||
fileNames.pop()
|
||||
obj[note] = fileNames.join('.')
|
||||
|
||||
return obj
|
||||
}, {})
|
||||
})
|
||||
|
||||
const unsubscribe = noteEventBus.addEventBusListener(
|
||||
({ path, currentNoteSHA }) => {
|
||||
@@ -93,6 +106,7 @@ export const useNote = (user: Ref<string>, repo: Ref<string>) => {
|
||||
})
|
||||
|
||||
return {
|
||||
titles,
|
||||
readme,
|
||||
notFound,
|
||||
stackedNotes
|
||||
|
||||
27
src/hooks/useNoteOverlay.hook.ts
Normal file
27
src/hooks/useNoteOverlay.hook.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { computed, onMounted } from '@vue/runtime-core'
|
||||
|
||||
import { useOverlay } from '@/hooks/useOverlay.hook'
|
||||
|
||||
const BOOKMARK_WIDTH = 2
|
||||
const NOTE_WIDTH = 620
|
||||
|
||||
export const useNoteOverlay = (className: string, index: number) => {
|
||||
const { x } = useOverlay()
|
||||
const displayNoteOverlay = computed(() => x.value > index * NOTE_WIDTH)
|
||||
|
||||
onMounted(() => {
|
||||
const noteElement = document.querySelector(
|
||||
`.${className}`
|
||||
) as HTMLElement | null
|
||||
|
||||
if (!noteElement) {
|
||||
return
|
||||
}
|
||||
|
||||
noteElement.style.left = `${(index + 1) * BOOKMARK_WIDTH}rem`
|
||||
})
|
||||
|
||||
return {
|
||||
displayNoteOverlay
|
||||
}
|
||||
}
|
||||
27
src/hooks/useOverlay.hook.ts
Normal file
27
src/hooks/useOverlay.hook.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
import { useEventListener } from '@vueuse/core'
|
||||
|
||||
export const useOverlay = () => {
|
||||
const x = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
const element = document.querySelector('body')
|
||||
|
||||
useEventListener(
|
||||
element,
|
||||
'scroll',
|
||||
(e) => {
|
||||
const target = e.target as HTMLElement
|
||||
x.value = target.scrollLeft
|
||||
},
|
||||
{
|
||||
passive: true,
|
||||
capture: false
|
||||
}
|
||||
)
|
||||
})
|
||||
return {
|
||||
x
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,13 @@
|
||||
|
||||
html {
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Courier Prime', monospace;
|
||||
text-align: center;
|
||||
height: 100vh;
|
||||
// width: 5000px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
|
||||
@@ -27,15 +27,16 @@
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="home content" v-else>
|
||||
<hr v-if="notFound" />
|
||||
<div v-if="notFound" class="columns is-centered">
|
||||
<div v-else-if="notFound">
|
||||
<hr />
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-one-third notification is-warning" v-if="notFound">
|
||||
Not found.
|
||||
</div>
|
||||
</div>
|
||||
<div class="note-container">
|
||||
<div class="readme">
|
||||
</div>
|
||||
<div class="home content note-container" v-else>
|
||||
<div class="readme note">
|
||||
<h1 class="title is-1">
|
||||
<router-link
|
||||
:to="{ name: 'Home', params: { user, repo } }"
|
||||
@@ -49,14 +50,15 @@
|
||||
</div>
|
||||
<stacked-note
|
||||
class="note"
|
||||
v-for="stackedNote in stackedNotes"
|
||||
v-for="(stackedNote, index) in stackedNotes"
|
||||
:key="stackedNote"
|
||||
:index="index"
|
||||
:user="user"
|
||||
:repo="repo"
|
||||
:sha="stackedNote"
|
||||
:title="titles[stackedNote]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -79,6 +81,7 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const refProps = toRefs(props)
|
||||
|
||||
return {
|
||||
...useNote(refProps.user, refProps.repo),
|
||||
...useForm(),
|
||||
@@ -91,20 +94,43 @@ export default defineComponent({
|
||||
<style lang="scss" scoped>
|
||||
.home {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
.readme {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
padding: 0 2rem 1rem;
|
||||
}
|
||||
|
||||
.note {
|
||||
text-align: left;
|
||||
overflow-y: auto;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
background-color: #fff;
|
||||
|
||||
&:not(:first-child) {
|
||||
border-top: 1px solid rgba(18, 19, 58, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 769px) {
|
||||
.readme,
|
||||
.note {
|
||||
min-width: 620px;
|
||||
max-width: 720px;
|
||||
max-width: 620px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.note-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
@media screen and (max-width: 768px) {
|
||||
.home {
|
||||
flex-wrap: wrap;
|
||||
|
||||
.note {
|
||||
position: initial;
|
||||
width: 100vw;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user