Migrated 'Glass Surface' component.

This commit is contained in:
snepsnepy
2025-07-21 15:59:37 +03:00
parent 6f7b18429b
commit 04e1712765
5 changed files with 594 additions and 1 deletions

View File

@@ -0,0 +1,261 @@
<template>
<TabbedLayout>
<template #preview>
<div class="relative overflow-y-auto no-scrollbar demo-container">
<GlassSurface
:key="key"
:width="360"
:height="100"
:border-radius="borderRadius"
:background-opacity="backgroundOpacity"
:saturation="saturation"
:border-width="borderWidth"
:brightness="brightness"
:opacity="opacity"
:blur="blur"
:displace="displace"
:distortion-scale="distortionScale"
:red-offset="redOffset"
:green-offset="greenOffset"
:blue-offset="blueOffset"
style="position: sticky; top: 50%; transform: translateY(-50%); z-index: 10"
/>
<div class="absolute flex flex-col items-center gap-6 top-0 left-0 right-0">
<div
class="absolute translate-y-1/2 top-12 text-4xl font-bold text-[#27FF64] z-0 whitespace-nowrap text-center"
>
Try scrolling.
</div>
<!-- Top Spacer -->
<div class="h-60 w-full" />
<!-- Image Blocks -->
<div v-for="(item, index) in imageBlocks" :key="index" class="relative">
<img :src="item.src" class="w-128 rounded-2xl object-cover grayscale-100" />
<div
class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 font-extrabold text-center leading-[100%] text-[3rem] min-w-72"
>
{{ item.text }}
</div>
</div>
<!-- Bottom Spacer -->
<div class="h-60 w-full" />
</div>
</div>
<Customize>
<PreviewSlider title="Border Radius" v-model="borderRadius" :min="0" :max="50" :step="1" />
<PreviewSlider title="Background Opacity" v-model="backgroundOpacity" :min="0" :max="1" :step="0.01" />
<PreviewSlider title="Saturation" v-model="saturation" :min="0" :max="3" :step="1" />
<PreviewSlider title="Border Width" v-model="borderWidth" :min="0" :max="0.2" :step="0.01" />
<PreviewSlider title="Brightness" v-model="brightness" :min="0" :max="100" :step="1" />
<PreviewSlider title="Opacity" v-model="opacity" :min="0" :max="1" :step="0.01" />
<PreviewSlider title="Blur" v-model="blur" :min="0" :max="30" :step="1" />
<PreviewSlider title="Displace" v-model="displace" :min="0" :max="5" :step="0.1" />
<PreviewSlider title="Distortion Scale" v-model="distortionScale" :min="-300" :max="300" :step="1" />
<PreviewSlider title="Red Offset" v-model="redOffset" :min="-50" :max="50" :step="1" />
<PreviewSlider title="Green Offset" v-model="greenOffset" :min="-50" :max="50" :step="1" />
<PreviewSlider title="Blue Offset" v-model="blueOffset" :min="-50" :max="50" :step="1" />
</Customize>
<PropTable :data="propData" />
</template>
<template #code>
<CodeExample :code-object="glassSurface" />
</template>
<template #cli>
<CliInstallation :command="glassSurface.cli" />
</template>
</TabbedLayout>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import TabbedLayout from '../../components/common/TabbedLayout.vue';
import PropTable from '../../components/common/PropTable.vue';
import CliInstallation from '../../components/code/CliInstallation.vue';
import CodeExample from '../../components/code/CodeExample.vue';
import Customize from '../../components/common/Customize.vue';
import PreviewSlider from '../../components/common/PreviewSlider.vue';
import GlassSurface from '../../content/Components/GlassSurface/GlassSurface.vue';
import { glassSurface } from '@/constants/code/Components/glassSurfaceCode';
import { useForceRerender } from '@/composables/useForceRerender';
const { rerenderKey: key, forceRerender } = useForceRerender();
const borderRadius = ref(50);
const backgroundOpacity = ref(0.1);
const saturation = ref(1);
const borderWidth = ref(0.07);
const brightness = ref(50);
const opacity = ref(0.93);
const blur = ref(11);
const displace = ref(0.5);
const distortionScale = ref(-80);
const redOffset = ref(0);
const greenOffset = ref(10);
const blueOffset = ref(20);
watch(
() => [
borderWidth.value,
brightness.value,
opacity.value,
blur.value,
displace.value,
distortionScale.value,
redOffset.value,
greenOffset.value,
blueOffset.value
],
() => {
forceRerender();
}
);
const imageBlocks = [
{
src: 'https://images.unsplash.com/photo-1500673587002-1d2548cfba1b?q=80&w=1740&auto=format&fit=crop',
text: 'The Summer Of Glass'
},
{
src: 'https://images.unsplash.com/photo-1594576547505-1be67997401e?q=80&w=1932&auto=format&fit=crop',
text: 'Can Hold Any Content'
},
{
src: 'https://images.unsplash.com/photo-1543127172-4b33cb699e35?q=80&w=1674&auto=format&fit=crop',
text: 'Has Built-In Fallback'
}
];
const propData = [
{
name: 'width',
type: 'number | string',
default: '200',
description: "Width of the glass surface (pixels or CSS value like '100%')"
},
{
name: 'height',
type: 'number | string',
default: '80',
description: "Height of the glass surface (pixels or CSS value like '100vh')"
},
{
name: 'borderRadius',
type: 'number',
default: '20',
description: 'Border radius in pixels'
},
{
name: 'borderWidth',
type: 'number',
default: '0.07',
description: 'Border width factor for displacement map'
},
{
name: 'brightness',
type: 'number',
default: '50',
description: 'Brightness percentage for displacement map'
},
{
name: 'opacity',
type: 'number',
default: '0.93',
description: 'Opacity of displacement map elements'
},
{
name: 'blur',
type: 'number',
default: '11',
description: 'Input blur amount in pixels'
},
{
name: 'displace',
type: 'number',
default: '0',
description: 'Output blur (stdDeviation)'
},
{
name: 'backgroundOpacity',
type: 'number',
default: '0',
description: 'Background frost opacity (0-1)'
},
{
name: 'saturation',
type: 'number',
default: '1',
description: 'Backdrop filter saturation factor'
},
{
name: 'distortionScale',
type: 'number',
default: '-180',
description: 'Main displacement scale'
},
{
name: 'redOffset',
type: 'number',
default: '0',
description: 'Red channel extra displacement offset'
},
{
name: 'greenOffset',
type: 'number',
default: '10',
description: 'Green channel extra displacement offset'
},
{
name: 'blueOffset',
type: 'number',
default: '20',
description: 'Blue channel extra displacement offset'
},
{
name: 'xChannel',
type: "'R' | 'G' | 'B'",
default: "'R'",
description: 'X displacement channel selector'
},
{
name: 'yChannel',
type: "'R' | 'G' | 'B'",
default: "'G'",
description: 'Y displacement channel selector'
},
{
name: 'mixBlendMode',
type: 'BlendMode',
default: "'difference'",
description: 'Mix blend mode for displacement map'
},
{
name: 'className',
type: 'string',
default: "''",
description: 'Additional CSS class names'
},
{
name: 'style',
type: 'CSSProperties',
default: '{}',
description: 'Inline styles object'
}
];
</script>
<style scoped>
.demo-container {
padding: 0;
}
.demo-container::-webkit-scrollbar {
display: none;
}
</style>