Remove v-if prop anti-pattern, clean up, add reader mode
This commit is contained in:
parent
3853e8fa20
commit
9386c1d158
|
@ -1 +1 @@
|
||||||
[{"D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\transitions.scss":"1","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\TransitionY.vue":"2","D:\\Software\\Development\\Websites\\enderman.ch\\index\\app.vue":"3","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\EMail.vue":"4","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\about.vue":"5","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\index.vue":"6","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\projects.vue":"7","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\social.vue":"8","D:\\Software\\Development\\Websites\\enderman.ch\\index\\layouts\\Card.vue":"9","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Options.vue":"10","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Flooter.vue":"11","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\SwipeControls.vue":"12","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Logo.vue":"13","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Route.vue":"14","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\Portal.vue":"15","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\ui\\Icon.vue":"16","D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\vuetify.scss":"17","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\[...slug].vue":"18","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\index.vue":"19","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\[slug].vue":"20"},{"size":165,"mtime":1700688268778,"hashOfConfig":"21"},{"size":1513,"mtime":1700430002840,"hashOfConfig":"21"},{"size":1550,"mtime":1700850776284,"hashOfConfig":"21"},{"size":804,"mtime":1700688952880,"hashOfConfig":"21"},{"size":2135,"mtime":1700689265787,"hashOfConfig":"21"},{"size":3117,"mtime":1700689271383,"hashOfConfig":"21"},{"size":2304,"mtime":1700689265769,"hashOfConfig":"21"},{"size":3232,"mtime":1700689265781,"hashOfConfig":"21"},{"size":1623,"mtime":1700748530633,"hashOfConfig":"21"},{"size":2187,"mtime":1706788559308,"hashOfConfig":"22"},{"size":2067,"mtime":1708180203174,"hashOfConfig":"22"},{"size":1236,"mtime":1706205683132,"hashOfConfig":"22"},{"size":1135,"mtime":1706030243608,"hashOfConfig":"22"},{"size":979,"mtime":1706003786966,"hashOfConfig":"22"},{"size":16968,"mtime":1708180277353,"hashOfConfig":"22"},{"size":935,"mtime":1706445231843,"hashOfConfig":"22"},{"size":120,"mtime":1706789613657,"hashOfConfig":"23"},{"size":1988,"mtime":1708191547889,"hashOfConfig":"22"},{"size":2560,"mtime":1708202402381,"hashOfConfig":"22"},{"size":983,"mtime":1708206997656,"hashOfConfig":"22"},"5tgxr3","1nljphs","1lk8nat"]
|
[{"D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\transitions.scss":"1","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\TransitionY.vue":"2","D:\\Software\\Development\\Websites\\enderman.ch\\index\\app.vue":"3","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\EMail.vue":"4","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\about.vue":"5","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\index.vue":"6","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\projects.vue":"7","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\social.vue":"8","D:\\Software\\Development\\Websites\\enderman.ch\\index\\layouts\\Card.vue":"9","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Options.vue":"10","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Flooter.vue":"11","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\SwipeControls.vue":"12","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Logo.vue":"13","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\blocks\\Route.vue":"14","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\animations\\Portal.vue":"15","D:\\Software\\Development\\Websites\\enderman.ch\\index\\components\\ui\\Icon.vue":"16","D:\\Software\\Development\\Websites\\enderman.ch\\index\\assets\\styles\\vuetify.scss":"17","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\[...slug].vue":"18","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\index.vue":"19","D:\\Software\\Development\\Websites\\enderman.ch\\index\\pages\\blog\\[slug].vue":"20"},{"size":165,"mtime":1700688268778,"hashOfConfig":"21"},{"size":1513,"mtime":1700430002840,"hashOfConfig":"21"},{"size":1550,"mtime":1700850776284,"hashOfConfig":"21"},{"size":804,"mtime":1700688952880,"hashOfConfig":"21"},{"size":2135,"mtime":1700689265787,"hashOfConfig":"21"},{"size":3117,"mtime":1700689271383,"hashOfConfig":"21"},{"size":2304,"mtime":1700689265769,"hashOfConfig":"21"},{"size":3232,"mtime":1700689265781,"hashOfConfig":"21"},{"size":1623,"mtime":1700748530633,"hashOfConfig":"21"},{"size":3065,"mtime":1708254606285,"hashOfConfig":"22"},{"size":1132,"mtime":1708254584095,"hashOfConfig":"22"},{"size":1269,"mtime":1708255068679,"hashOfConfig":"22"},{"size":1147,"mtime":1708248797872,"hashOfConfig":"22"},{"size":979,"mtime":1706003786966,"hashOfConfig":"22"},{"size":16968,"mtime":1708180277353,"hashOfConfig":"22"},{"size":935,"mtime":1706445231843,"hashOfConfig":"22"},{"size":120,"mtime":1706789613657,"hashOfConfig":"23"},{"size":1988,"mtime":1708191547889,"hashOfConfig":"22"},{"size":2560,"mtime":1708202402381,"hashOfConfig":"22"},{"size":983,"mtime":1708206997656,"hashOfConfig":"22"},"5tgxr3","1nljphs","1lk8nat"]
|
25
app.vue
25
app.vue
|
@ -1,6 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const config = useAppConfig()
|
const config = useAppConfig()
|
||||||
|
const vdisp = ref(useVDisplay())
|
||||||
const theme = useVThemeSSR()
|
const theme = useVThemeSSR()
|
||||||
|
const { reader } = storeToRefs(usePageStore())
|
||||||
|
|
||||||
useHead({
|
useHead({
|
||||||
titleTemplate: (chunk?) => {
|
titleTemplate: (chunk?) => {
|
||||||
|
@ -17,10 +19,11 @@ useHead({
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
id="ender-layout"
|
id="ender-layout"
|
||||||
class="d-flex flex-column align-items-center pt-sm-5 h-100"
|
class="p-animated d-flex flex-column align-items-center h-100"
|
||||||
|
:class="{ 'pt-sm-5': !reader }"
|
||||||
>
|
>
|
||||||
<AClientOnly appear render="xs" mode="out-in">
|
<AClientOnly appear mode="out-in">
|
||||||
<SwipeControls />
|
<SwipeControls v-if="vdisp.xs" />
|
||||||
</AClientOnly>
|
</AClientOnly>
|
||||||
|
|
||||||
<NuxtLayout
|
<NuxtLayout
|
||||||
|
@ -30,30 +33,28 @@ useHead({
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<AClientOnly
|
<AClientOnly
|
||||||
appear
|
appear
|
||||||
render="xs"
|
|
||||||
mode="in-out"
|
mode="in-out"
|
||||||
enter="animate__animated animate__delay-1s animate__fadeIn"
|
enter="animate__animated animate__delay-1s animate__fadeIn"
|
||||||
leave="animate__animated animate__fadeOut"
|
leave="animate__animated animate__fadeOut"
|
||||||
>
|
>
|
||||||
<Flooter opaque />
|
<Flooter v-if="vdisp.xs" opaque />
|
||||||
</AClientOnly>
|
</AClientOnly>
|
||||||
</template>
|
</template>
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ClientOnly>
|
|
||||||
<template #fallback> </template>
|
|
||||||
<Portal layout="#ender-layout" animate randomize fade />
|
|
||||||
</ClientOnly>
|
|
||||||
|
|
||||||
<AClientOnly
|
<AClientOnly
|
||||||
appear
|
appear
|
||||||
render="sm-up"
|
|
||||||
mode="out-in"
|
mode="out-in"
|
||||||
enter="animate__animated animate__delay-1s animate__fadeInUpBig animate__slow"
|
enter="animate__animated animate__delay-1s animate__fadeInUpBig animate__slow"
|
||||||
leave="animate__animated animate__fadeOutDown"
|
leave="animate__animated animate__fadeOutDown"
|
||||||
>
|
>
|
||||||
<Flooter class="floaty mb-2 px-2" />
|
<Flooter v-if="vdisp.smAndUp" class="floaty mb-2 px-2" />
|
||||||
</AClientOnly>
|
</AClientOnly>
|
||||||
|
|
||||||
|
<ClientOnly>
|
||||||
|
<template #fallback> </template>
|
||||||
|
<Portal layout="#ender-layout" animate randomize fade />
|
||||||
|
</ClientOnly>
|
||||||
</VThemeProvider>
|
</VThemeProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -61,6 +61,10 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper classes that don't exist in Bootstrap.
|
// Helper classes that don't exist in Bootstrap.
|
||||||
|
.mh-0 {
|
||||||
|
max-height: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
.nobr {
|
.nobr {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +116,14 @@ body {
|
||||||
word-break: keep-all;
|
word-break: keep-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.h-animated {
|
||||||
|
transition: max-height 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-animated {
|
||||||
|
transition: padding 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
// Query-overridable classes.
|
// Query-overridable classes.
|
||||||
.background {
|
.background {
|
||||||
background-color: rgb(0 0 0 / 50%);
|
background-color: rgb(0 0 0 / 50%);
|
||||||
|
@ -122,6 +134,10 @@ body {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
.dialog {
|
.dialog {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
||||||
|
@ -257,6 +273,10 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
.radial-gradient {
|
.radial-gradient {
|
||||||
background: radial-gradient(
|
background: radial-gradient(
|
||||||
circle at left,
|
circle at left,
|
||||||
|
@ -300,8 +320,6 @@ body {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
||||||
padding: 0.5rem;
|
|
||||||
|
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
background-color: rgb(153 153 255 / 10%);
|
background-color: rgb(153 153 255 / 10%);
|
||||||
|
|
||||||
|
@ -313,20 +331,32 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&-thumb {
|
&-thumb {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
> img {
|
> img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 280px;
|
height: 100%;
|
||||||
|
max-height: 280px;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-tags {
|
||||||
|
> span {
|
||||||
|
padding: 0.35em 0.65em;
|
||||||
|
font-size: 0.85em;
|
||||||
|
|
||||||
|
background-color: rgb(153 153 255 / 10%);
|
||||||
|
|
||||||
|
border: 1px solid rgb(153 153 255 / 60%);
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-details {
|
||||||
|
}
|
||||||
|
|
||||||
&-preamble {
|
&-preamble {
|
||||||
&-thumb {
|
&-thumb {
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
|
@ -334,12 +364,18 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
|
:is(h1, h2, h3, h4, h5, h6) {
|
||||||
|
font-family: Alexandria, sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@extend %link;
|
@extend %link;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
padding-left: 0.5rem;
|
img {
|
||||||
|
max-height: 400px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,10 +426,10 @@ body {
|
||||||
|
|
||||||
&-thumb {
|
&-thumb {
|
||||||
min-width: 352px;
|
min-width: 352px;
|
||||||
|
max-height: 198px;
|
||||||
|
|
||||||
> img {
|
> img {
|
||||||
max-width: 352px;
|
max-width: 352px;
|
||||||
height: 198px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
<script setup>
|
|
||||||
console.log('Transition started')
|
|
||||||
function enter(el, done) {
|
|
||||||
const width = getComputedStyle(el).width
|
|
||||||
console.log('@enter')
|
|
||||||
el.style.width = width
|
|
||||||
el.style.position = 'absolute'
|
|
||||||
el.style.visibility = 'hidden'
|
|
||||||
el.style.height = 'auto'
|
|
||||||
|
|
||||||
const height = getComputedStyle(el).height
|
|
||||||
|
|
||||||
el.style.width = ''
|
|
||||||
el.style.position = ''
|
|
||||||
el.style.visibility = ''
|
|
||||||
el.style.height = '0'
|
|
||||||
|
|
||||||
// Force repaint to make sure the
|
|
||||||
// animation is triggered correctly.
|
|
||||||
getComputedStyle(el).height
|
|
||||||
|
|
||||||
// Trigger the animation.
|
|
||||||
// We use `requestAnimationFrame` because we need
|
|
||||||
// to make sure the browser has finished
|
|
||||||
// painting after setting the `height`
|
|
||||||
// to `0` in the line above.
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
el.style.height = height
|
|
||||||
})
|
|
||||||
|
|
||||||
done()
|
|
||||||
}
|
|
||||||
|
|
||||||
function afterEnter(element) {
|
|
||||||
console.log('@after-enter')
|
|
||||||
element.style.height = 'auto'
|
|
||||||
}
|
|
||||||
|
|
||||||
function leave(element) {
|
|
||||||
console.log('@leave')
|
|
||||||
const height = getComputedStyle(element).height
|
|
||||||
|
|
||||||
element.style.height = height
|
|
||||||
|
|
||||||
// Force repaint to make sure the
|
|
||||||
// animation is triggered correctly.
|
|
||||||
getComputedStyle(element).height
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
element.style.height = '0'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Transition
|
|
||||||
name="expand"
|
|
||||||
@enter="enter"
|
|
||||||
@after-enter="afterEnter"
|
|
||||||
@leave="leave"
|
|
||||||
>
|
|
||||||
<slot />
|
|
||||||
</Transition>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
* {
|
|
||||||
will-change: height;
|
|
||||||
transform: translateZ(0);
|
|
||||||
backface-visibility: hidden;
|
|
||||||
perspective: 1000px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -2,35 +2,12 @@
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
|
|
||||||
type ModeOptions = 'in-out' | 'out-in' | 'default' | undefined
|
type ModeOptions = 'in-out' | 'out-in' | 'default' | undefined
|
||||||
type RenderOptions =
|
|
||||||
| 'never'
|
|
||||||
| 'always'
|
|
||||||
| 'xs'
|
|
||||||
| 'sm'
|
|
||||||
| 'sm-down'
|
|
||||||
| 'sm-up'
|
|
||||||
| 'md'
|
|
||||||
| 'md-down'
|
|
||||||
| 'md-up'
|
|
||||||
| 'lg'
|
|
||||||
| 'lg-down'
|
|
||||||
| 'lg-up'
|
|
||||||
| 'xl'
|
|
||||||
| 'xl-down'
|
|
||||||
| 'xl-up'
|
|
||||||
| 'xxl'
|
|
||||||
| undefined
|
|
||||||
|
|
||||||
const vdisp = ref(useVDisplay())
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
fallback: {
|
fallback: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
render: {
|
|
||||||
type: String as PropType<RenderOptions>,
|
|
||||||
default: 'always',
|
|
||||||
},
|
|
||||||
appear: {
|
appear: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -48,45 +25,6 @@ const props = defineProps({
|
||||||
default: 'animate__fadeOut',
|
default: 'animate__fadeOut',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const render = computed(() => {
|
|
||||||
switch (props.render) {
|
|
||||||
case 'never':
|
|
||||||
return false
|
|
||||||
case 'always':
|
|
||||||
return true
|
|
||||||
case 'xs':
|
|
||||||
return vdisp.value.xs
|
|
||||||
case 'sm':
|
|
||||||
return vdisp.value.sm
|
|
||||||
case 'sm-down':
|
|
||||||
return vdisp.value.smAndDown
|
|
||||||
case 'sm-up':
|
|
||||||
return vdisp.value.smAndUp
|
|
||||||
case 'md':
|
|
||||||
return vdisp.value.md
|
|
||||||
case 'md-down':
|
|
||||||
return vdisp.value.mdAndDown
|
|
||||||
case 'md-up':
|
|
||||||
return vdisp.value.mdAndUp
|
|
||||||
case 'lg':
|
|
||||||
return vdisp.value.lg
|
|
||||||
case 'lg-down':
|
|
||||||
return vdisp.value.lgAndDown
|
|
||||||
case 'lg-up':
|
|
||||||
return vdisp.value.lgAndUp
|
|
||||||
case 'xl':
|
|
||||||
return vdisp.value.xl
|
|
||||||
case 'xl-down':
|
|
||||||
return vdisp.value.xlAndDown
|
|
||||||
case 'xl-up':
|
|
||||||
return vdisp.value.xlAndUp
|
|
||||||
case 'xxl':
|
|
||||||
return vdisp.value.xxl
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -99,7 +37,7 @@ const render = computed(() => {
|
||||||
:enter-active-class="`animate__animated ${props.enter}`"
|
:enter-active-class="`animate__animated ${props.enter}`"
|
||||||
:leave-active-class="`animate__animated ${props.leave}`"
|
:leave-active-class="`animate__animated ${props.leave}`"
|
||||||
>
|
>
|
||||||
<slot v-if="render" />
|
<slot />
|
||||||
</Transition>
|
</Transition>
|
||||||
</ClientOnly>
|
</ClientOnly>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -4,14 +4,7 @@ const props = defineProps({
|
||||||
})
|
})
|
||||||
|
|
||||||
const config = useAppConfig()
|
const config = useAppConfig()
|
||||||
const fqdn = config.url.split('//')[1]
|
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear()
|
const currentYear = new Date().getFullYear()
|
||||||
const mailTemplate = `I've just found a bug on ${config.url} and would like to report it.%0D%0A%0D%0AWebsite version: ${
|
|
||||||
config.build.version
|
|
||||||
}%0D%0ABuild date: ${
|
|
||||||
config.build.date
|
|
||||||
}%0D%0ATimestamp: ${new Date().toISOString()}%0D%0A%0D%0A%0D%0ASteps to reproduce:%0D%0A{ Explain in detail what happened here, or attach a video/screenshot }%0D%0A%0D%0AAdditional information:%0D%0A{ Helpful information, such as developer console output / Leave empty if none }%0D%0A%0D%0A%0D%0A// Keep in mind that it's just a template, you can change it as you wish! :)`
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -25,19 +18,6 @@ const mailTemplate = `I've just found a bug on ${config.url} and would like to r
|
||||||
'text-shadow': !props.opaque,
|
'text-shadow': !props.opaque,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<EMail
|
|
||||||
:class="{
|
|
||||||
'link-hi-force-dark': !props.opaque,
|
|
||||||
'link-hi': props.opaque,
|
|
||||||
}"
|
|
||||||
:address="`contact@${fqdn}`"
|
|
||||||
:cc="`admin@${fqdn}`"
|
|
||||||
:subject="`Bug report: ${fqdn}`"
|
|
||||||
:body="mailTemplate"
|
|
||||||
>
|
|
||||||
<strong>Report a bug</strong>
|
|
||||||
</EMail>
|
|
||||||
<br />
|
|
||||||
© 2018-{{ currentYear }},
|
© 2018-{{ currentYear }},
|
||||||
<a
|
<a
|
||||||
:class="{
|
:class="{
|
||||||
|
|
|
@ -43,7 +43,7 @@ const props = defineProps({
|
||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="alex mb-0">{{ props.title }}</h1>
|
<h1 class="alex mb-0">{{ props.title }}</h1>
|
||||||
<Separator />
|
<Separator class="m-0" />
|
||||||
<p class="mb-0">{{ props.description }}</p>
|
<p class="mb-0">{{ props.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
|
|
@ -3,6 +3,14 @@ import cogIcon from '~/assets/images/icons/cog.png'
|
||||||
import pearlIcon from '~/assets/images/icons/pearl.gif'
|
import pearlIcon from '~/assets/images/icons/pearl.gif'
|
||||||
|
|
||||||
const theme = useVThemeSSR()
|
const theme = useVThemeSSR()
|
||||||
|
const config = useAppConfig()
|
||||||
|
const fqdn = config.url.split('//')[1]
|
||||||
|
|
||||||
|
const mailTemplate = `I've just found a bug on ${config.url} and would like to report it.%0D%0A%0D%0AWebsite version: ${
|
||||||
|
config.build.version
|
||||||
|
}%0D%0ABuild date: ${
|
||||||
|
config.build.date
|
||||||
|
}%0D%0ATimestamp: ${new Date().toISOString()}%0D%0A%0D%0A%0D%0ASteps to reproduce:%0D%0A{ Explain in detail what happened here, or attach a video/screenshot }%0D%0A%0D%0AAdditional information:%0D%0A{ Helpful information, such as developer console output / Leave empty if none }%0D%0A%0D%0A%0D%0A// Keep in mind that it's just a template, you can change it as you wish! :)`
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -48,7 +56,15 @@ const theme = useVThemeSSR()
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Report a bug
|
<EMail
|
||||||
|
class="link-hi"
|
||||||
|
:address="`contact@${fqdn}`"
|
||||||
|
:cc="`admin@${fqdn}`"
|
||||||
|
:subject="`Bug report: ${fqdn}`"
|
||||||
|
:body="mailTemplate"
|
||||||
|
>
|
||||||
|
<strong>Report a bug</strong>
|
||||||
|
</EMail>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VCardActions>
|
<VCardActions>
|
||||||
<VSpacer></VSpacer>
|
<VSpacer></VSpacer>
|
||||||
|
|
|
@ -13,7 +13,7 @@ const props = defineProps({
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<hr
|
<hr
|
||||||
class="radial-gradient m-0 border-0 w-100"
|
class="separator radial-gradient border-0"
|
||||||
:style="{ height: props.height + 'px' }"
|
:style="{ height: props.height + 'px' }"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -8,7 +8,9 @@ const { pages } = storeToRefs(pageStore)
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const state = computed(() => {
|
const state = computed(() => {
|
||||||
const i = pages.value.indexOf(
|
const i = pages.value.indexOf(
|
||||||
pages.value.find((page) => page.path === route.fullPath)!,
|
pages.value.find(
|
||||||
|
(page) => page.path === '/' + route.fullPath.split('/')[1],
|
||||||
|
)!,
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<template></template>
|
|
|
@ -1 +0,0 @@
|
||||||
<template></template>
|
|
|
@ -1 +0,0 @@
|
||||||
<template></template>
|
|
|
@ -4,7 +4,7 @@ description: We dive in deep into the Windows context menu and how to customize
|
||||||
created: 2023-08-13T15:51:19Z
|
created: 2023-08-13T15:51:19Z
|
||||||
updated: 2024-02-18T21:32:12Z
|
updated: 2024-02-18T21:32:12Z
|
||||||
draft: false
|
draft: false
|
||||||
tags: ['windows', 'context-menu']
|
tags: ['windows', 'context-menu', 'customization', 'registry', 'shell', 'shell-extensions', 'context-menu-handlers']
|
||||||
thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png'
|
thumbnail: '/images/blog/thumbnails/the-windows-context-menu.png'
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const card = ref<HTMLElement | null>(null)
|
const card = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
const pageStore = usePageStore()
|
const { pages, reader } = storeToRefs(usePageStore())
|
||||||
const { pages } = storeToRefs(pageStore)
|
|
||||||
const swipe = useSwipe(card, {
|
const swipe = useSwipe(card, {
|
||||||
passive: true,
|
passive: true,
|
||||||
onSwipeEnd: (_touch: TouchEvent, _direction: UseSwipeDirection) => {
|
onSwipeEnd: (_touch: TouchEvent, _direction: UseSwipeDirection) => {
|
||||||
|
@ -41,7 +41,11 @@ const swipe = useSwipe(card, {
|
||||||
<template>
|
<template>
|
||||||
<main
|
<main
|
||||||
ref="card"
|
ref="card"
|
||||||
class="dimensions background rounded-1-sm overflow-auto d-flex flex-column gap-3 gap-sm-2 px-4 pt-4 pb-3"
|
class="dimensions background h-animated overflow-auto d-flex flex-column gap-3 gap-sm-2 px-4 pt-4 pb-3"
|
||||||
|
:class="{
|
||||||
|
'rounded-1-sm': !reader,
|
||||||
|
'mh-0': reader,
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<Options />
|
<Options />
|
||||||
<Navigation />
|
<Navigation />
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export default defineNuxtRouteMiddleware((to, from) => {
|
||||||
|
const { reader } = storeToRefs(usePageStore())
|
||||||
|
|
||||||
|
reader.value = /\/blog\/(.*)/.test(to.path)
|
||||||
|
})
|
|
@ -43,14 +43,14 @@ useHead({
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<h3 class="alex">About me</h3>
|
<h3 class="alex">About me</h3>
|
||||||
<hr />
|
<Separator />
|
||||||
<p>
|
<p>
|
||||||
<strong>🚧 This page is currently under construction.</strong> Expect a
|
<strong>🚧 This page is currently under construction.</strong> Expect a
|
||||||
lot more content to be added as time passes.
|
lot more content to be added as time passes.
|
||||||
<em>Please report all bugs you encounter via the link in the footer</em>,
|
<em>Please report all bugs you encounter via the link in the footer</em>,
|
||||||
I will make sure to sand them down.
|
I will make sure to sand them down.
|
||||||
</p>
|
</p>
|
||||||
<hr />
|
<Separator />
|
||||||
<p>
|
<p>
|
||||||
Nice to meet you! I'm Andrew, a {{ age }}-year-old guy from Kaluga,
|
Nice to meet you! I'm Andrew, a {{ age }}-year-old guy from Kaluga,
|
||||||
Russia. I have been developing software since I was 10, and I have always
|
Russia. I have been developing software since I was 10, and I have always
|
||||||
|
|
|
@ -32,20 +32,36 @@ import { formatDate } from 'date-fns'
|
||||||
class="rounded-4"
|
class="rounded-4"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="w-100">
|
||||||
<h3 class="post-title alex">{{ post.title }}</h3>
|
<h3 class="post-title alex">{{ post.title }}</h3>
|
||||||
<p class="post-description">{{ post.description }}</p>
|
<p class="post-description mb-0">{{ post.description }}</p>
|
||||||
|
|
||||||
<div class="row">
|
<div class="post-tags d-flex flex-row flex-wrap gap-2 py-2">
|
||||||
<div class="col-6 d-flex flex-row gap-1 align-items-center">
|
<span
|
||||||
|
v-for="(tag, index) in post.tags.slice(0, 3)"
|
||||||
|
:key="index"
|
||||||
|
class="nobr"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</span>
|
||||||
|
<span v-if="post.tags.length > 3" class="nobr">
|
||||||
|
{{ post.tags.length - 3 }} more
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator class="m-0" />
|
||||||
|
|
||||||
|
<div class="post-details py-2">
|
||||||
|
<div class="d-flex flex-row gap-1 align-items-center">
|
||||||
<iconify-icon icon="mdi:calendar" />
|
<iconify-icon icon="mdi:calendar" />
|
||||||
<small class="nobr">
|
<small class="nobr">
|
||||||
{{ formatDate(post.created, 'LLLL do, y – HH:mm') }}
|
{{ formatDate(post.created, 'LLLL do, y – HH:mm') }}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<div v-if="post.updated" class="row">
|
v-if="post.updated"
|
||||||
<div class="col-12 d-flex flex-row gap-1 align-items-center">
|
class="d-flex flex-row gap-1 align-items-center"
|
||||||
|
>
|
||||||
<iconify-icon icon="mdi:pencil" />
|
<iconify-icon icon="mdi:pencil" />
|
||||||
<small class="nobr">
|
<small class="nobr">
|
||||||
{{ formatDate(post.updated, 'LLLL do, y – HH:mm') }}
|
{{ formatDate(post.updated, 'LLLL do, y – HH:mm') }}
|
||||||
|
@ -54,7 +70,9 @@ import { formatDate } from 'date-fns'
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-pocket d-flex flex-row gap-1 align-items-center">
|
<div
|
||||||
|
class="post-pocket d-flex flex-row gap-1 align-items-center p-2"
|
||||||
|
>
|
||||||
<iconify-icon icon="mdi:clock-outline" />
|
<iconify-icon icon="mdi:clock-outline" />
|
||||||
<small class="nobr font-monospace font-small">
|
<small class="nobr font-monospace font-small">
|
||||||
{{ post.readingTime.text }}
|
{{ post.readingTime.text }}
|
||||||
|
|
|
@ -69,14 +69,14 @@ useHead({
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<h3 class="alex">Projects</h3>
|
<h3 class="alex">Projects</h3>
|
||||||
<hr />
|
<Separator />
|
||||||
<p>
|
<p>
|
||||||
<strong>🚧 This page is currently under construction.</strong> Expect a
|
<strong>🚧 This page is currently under construction.</strong> Expect a
|
||||||
lot more content to be added as time passes.
|
lot more content to be added as time passes.
|
||||||
<em>Please report all bugs you encounter via the link in the footer</em>,
|
<em>Please report all bugs you encounter via the link in the footer</em>,
|
||||||
I will make sure to sand them down.
|
I will make sure to sand them down.
|
||||||
</p>
|
</p>
|
||||||
<hr />
|
<Separator />
|
||||||
<p><strong>My current projects are:</strong></p>
|
<p><strong>My current projects are:</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(item, index) in projects" :key="index">
|
<li v-for="(item, index) in projects" :key="index">
|
||||||
|
|
|
@ -117,14 +117,14 @@ useHead({
|
||||||
<template>
|
<template>
|
||||||
<section>
|
<section>
|
||||||
<h3 class="alex">Online presence</h3>
|
<h3 class="alex">Online presence</h3>
|
||||||
<hr />
|
<Separator />
|
||||||
<p>
|
<p>
|
||||||
<strong>🚧 This page is currently under construction.</strong> Expect a
|
<strong>🚧 This page is currently under construction.</strong> Expect a
|
||||||
lot more content to be added as time passes.
|
lot more content to be added as time passes.
|
||||||
<em>Please report all bugs you encounter via the link in the footer</em>,
|
<em>Please report all bugs you encounter via the link in the footer</em>,
|
||||||
I will make sure to sand them down.
|
I will make sure to sand them down.
|
||||||
</p>
|
</p>
|
||||||
<hr />
|
<Separator />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
<h5 class="alex">Social media</h5>
|
<h5 class="alex">Social media</h5>
|
||||||
|
|
|
@ -50,6 +50,8 @@ export const usePageStore = defineStore('page', () => {
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const reader = ref(false)
|
||||||
|
|
||||||
function _autoFetchPages() {
|
function _autoFetchPages() {
|
||||||
while (pages.value.length) pages.value.pop()
|
while (pages.value.length) pages.value.pop()
|
||||||
|
|
||||||
|
@ -68,5 +70,6 @@ export const usePageStore = defineStore('page', () => {
|
||||||
description,
|
description,
|
||||||
keywords,
|
keywords,
|
||||||
pages,
|
pages,
|
||||||
|
reader,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue