Adds the whole disclaimer feature
This commit is contained in:
257
resources/js/Pages/Disclaimer.vue
Normal file
257
resources/js/Pages/Disclaimer.vue
Normal file
@@ -0,0 +1,257 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { Head } from '@inertiajs/vue3'
|
||||
import { ArrowLeftIcon } from '@heroicons/vue/24/outline'
|
||||
import { marked } from 'marked'
|
||||
import AppLayout from '@/Layouts/AppLayout.vue'
|
||||
import AppButton from '@/Components/AppButton.vue'
|
||||
|
||||
defineOptions({ layout: AppLayout })
|
||||
|
||||
const props = defineProps({
|
||||
content: String,
|
||||
})
|
||||
|
||||
const parsedContent = computed(() => {
|
||||
if (!props.content) return ''
|
||||
return marked(props.content)
|
||||
})
|
||||
|
||||
const bottomBackButtonRef = ref(null)
|
||||
const showStickyBack = ref(false)
|
||||
|
||||
let observer = null
|
||||
|
||||
onMounted(() => {
|
||||
if (!bottomBackButtonRef.value) return
|
||||
observer = new IntersectionObserver(
|
||||
([entry]) => { showStickyBack.value = !entry.isIntersecting },
|
||||
{ threshold: 0 }
|
||||
)
|
||||
observer.observe(bottomBackButtonRef.value.$el || bottomBackButtonRef.value)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
observer?.disconnect()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Disclaimer" />
|
||||
|
||||
<div class="max-w-3xl mx-auto px-4 py-10">
|
||||
<!-- Sticky back button — appears when bottom back button scrolls out of view -->
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-200 ease-out"
|
||||
enter-from-class="opacity-0 translate-x-4"
|
||||
enter-to-class="opacity-100 translate-x-0"
|
||||
leave-active-class="transition-all duration-150 ease-in"
|
||||
leave-from-class="opacity-100 translate-x-0"
|
||||
leave-to-class="opacity-0 translate-x-4"
|
||||
>
|
||||
<div v-if="showStickyBack" class="fixed top-[88px] right-6 z-40">
|
||||
<AppButton variant="ghost" size="lg" href="/">
|
||||
<ArrowLeftIcon class="h-5 w-5" />
|
||||
Back
|
||||
</AppButton>
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<!-- Page heading -->
|
||||
<div class="mb-10">
|
||||
<h1 class="text-2xl font-bold text-white">Disclaimer</h1>
|
||||
<div class="h-px bg-gradient-to-r from-primary/40 via-primary/10 to-transparent mt-4"></div>
|
||||
</div>
|
||||
|
||||
<!-- Rendered markdown content -->
|
||||
<div class="prose-dark" v-html="parsedContent" />
|
||||
|
||||
<!-- Bottom back button -->
|
||||
<div class="mt-12 pt-8 border-t border-white/[0.06]">
|
||||
<AppButton ref="bottomBackButtonRef" variant="ghost" size="lg" href="/">
|
||||
<ArrowLeftIcon class="h-5 w-5" />
|
||||
Back
|
||||
</AppButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.prose-dark :deep(h1) {
|
||||
color: #ffffff;
|
||||
font-size: 1.875rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(h2) {
|
||||
color: #ffffff;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
margin-top: 1.75rem;
|
||||
margin-bottom: 0.875rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(h3) {
|
||||
color: #ffffff;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(h4) {
|
||||
color: #ffffff;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.4;
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.625rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(p) {
|
||||
color: #d1d5db; /* text-gray-300 */
|
||||
line-height: 1.75;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(a) {
|
||||
color: #d1ec51; /* text-primary */
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
transition: color 0.15s ease;
|
||||
}
|
||||
|
||||
.prose-dark :deep(a:hover) {
|
||||
color: #b5d136; /* text-primary-dark */
|
||||
}
|
||||
|
||||
.prose-dark :deep(ul) {
|
||||
color: #d1d5db;
|
||||
list-style: none;
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(ul li) {
|
||||
position: relative;
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.prose-dark :deep(ul li::before) {
|
||||
content: '—';
|
||||
color: #d1ec51; /* text-primary */
|
||||
position: absolute;
|
||||
left: -1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prose-dark :deep(ol) {
|
||||
color: #d1d5db;
|
||||
list-style: none;
|
||||
padding-left: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
counter-reset: ol-counter;
|
||||
}
|
||||
|
||||
.prose-dark :deep(ol li) {
|
||||
position: relative;
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.75;
|
||||
counter-increment: ol-counter;
|
||||
}
|
||||
|
||||
.prose-dark :deep(ol li::before) {
|
||||
content: counter(ol-counter) '.';
|
||||
color: #d1ec51; /* text-primary */
|
||||
position: absolute;
|
||||
left: -2rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prose-dark :deep(blockquote) {
|
||||
border-left: 3px solid #d1ec51; /* border-primary */
|
||||
padding-left: 1.25rem;
|
||||
margin: 1.5rem 0;
|
||||
font-style: italic;
|
||||
color: #9ca3af; /* text-gray-400 */
|
||||
}
|
||||
|
||||
.prose-dark :deep(blockquote p) {
|
||||
color: #9ca3af;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.prose-dark :deep(pre) {
|
||||
background-color: rgba(31, 41, 55, 0.5); /* bg-gray-800/50 */
|
||||
border: 1px solid rgba(75, 85, 99, 0.4);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.25rem;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(pre code) {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 0.875rem;
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.prose-dark :deep(code) {
|
||||
background-color: rgba(31, 41, 55, 0.5); /* bg-gray-800/50 */
|
||||
border: 1px solid rgba(75, 85, 99, 0.3);
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.125rem 0.375rem;
|
||||
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 0.875em;
|
||||
color: #d1ec51; /* text-primary */
|
||||
}
|
||||
|
||||
.prose-dark :deep(strong) {
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prose-dark :deep(em) {
|
||||
color: #d1d5db;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.prose-dark :deep(hr) {
|
||||
border: none;
|
||||
border-top: 1px solid #4b5563; /* border-gray-600 */
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.prose-dark :deep(table) {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.prose-dark :deep(th) {
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
padding: 0.625rem 0.875rem;
|
||||
border-bottom: 2px solid #4b5563;
|
||||
}
|
||||
|
||||
.prose-dark :deep(td) {
|
||||
color: #d1d5db;
|
||||
padding: 0.625rem 0.875rem;
|
||||
border-bottom: 1px solid rgba(75, 85, 99, 0.4);
|
||||
}
|
||||
|
||||
.prose-dark :deep(tr:last-child td) {
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user