feat: animated icon
0
Projects/kompose/docs/.env
Normal file → Executable file
0
Projects/kompose/docs/.gitignore
vendored
Normal file → Executable file
0
Projects/kompose/docs/.npmrc
Normal file → Executable file
0
Projects/kompose/docs/README.md
Normal file → Executable file
0
Projects/kompose/docs/app/app.config.ts
Normal file → Executable file
0
Projects/kompose/docs/app/app.vue
Normal file → Executable file
0
Projects/kompose/docs/app/assets/css/main.css
Normal file → Executable file
0
Projects/kompose/docs/app/components/AppFooter.vue
Normal file → Executable file
2
Projects/kompose/docs/app/components/AppHeader.vue
Normal file → Executable file
@@ -22,7 +22,7 @@ const { header } = useAppConfig()
|
||||
<template v-else #left>
|
||||
<div class="flex items-center gap-6">
|
||||
<NuxtLink :to="header?.to || '/'" class="flex items-center">
|
||||
<img src="/icon.svg" alt="kompose" class="size-7 mt-1 mr-2"></img>
|
||||
<AppIcon size="32px" class="mt-1 mr-2" />
|
||||
<AppLogo class="!text-2xl mt-1" />
|
||||
</NuxtLink>
|
||||
|
||||
|
||||
609
Projects/kompose/docs/app/components/AppIcon.vue
Normal file → Executable file
@@ -1,192 +1,445 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
<template>
|
||||
<div
|
||||
class="kompose-icon-wrapper"
|
||||
:class="{ 'is-clicked': isClicked, 'is-interactive': interactive }"
|
||||
@click="handleClick"
|
||||
@mouseenter="handleHover"
|
||||
@mouseleave="handleLeave"
|
||||
@touchstart="handleTouch"
|
||||
:style="{ width: size, height: size }"
|
||||
>
|
||||
<svg
|
||||
class="kompose-icon"
|
||||
viewBox="0 0 192 192"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<pattern id="carbon192" x="0" y="0" width="7.68" height="7.68" patternUnits="userSpaceOnUse">
|
||||
<rect width="7.68" height="7.68" fill="#0a0e27"></rect>
|
||||
<path d="M0,0 L3.84,3.84 M3.84,0 L7.68,3.84 M0,3.84 L3.84,7.68" stroke="#060815" stroke-width="1.5" opacity="0.5"></path>
|
||||
</pattern>
|
||||
|
||||
const props = defineProps({
|
||||
size: {
|
||||
type: Number,
|
||||
default: 512 // Default for PWA, can be 16, 32, 192, 512, etc.
|
||||
}
|
||||
<linearGradient id="bgGrad192" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#1a1d2e;stop-opacity:1"></stop>
|
||||
<stop offset="100%" style="stop-color:#0a0e27;stop-opacity:1"></stop>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="primaryGrad192" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" class="gradient-start" style="stop-color:#00DC82;stop-opacity:1"></stop>
|
||||
<stop offset="100%" class="gradient-end" style="stop-color:#00a86b;stop-opacity:1"></stop>
|
||||
</linearGradient>
|
||||
|
||||
<filter id="glow192">
|
||||
<feGaussianBlur stdDeviation="6" result="coloredBlur"></feGaussianBlur>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
|
||||
<filter id="intenseglow192">
|
||||
<feGaussianBlur stdDeviation="12" result="coloredBlur"></feGaussianBlur>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur"></feMergeNode>
|
||||
<feMergeNode in="SourceGraphic"></feMergeNode>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Background -->
|
||||
<rect class="bg-rect" width="192" height="192" rx="24" fill="url(#bgGrad192)"></rect>
|
||||
<rect class="carbon-pattern" width="192" height="192" rx="24" fill="url(#carbon192)" opacity="0.4"></rect>
|
||||
|
||||
<!-- Stylized K -->
|
||||
<g class="k-letter" transform="translate(48, 48)">
|
||||
<line class="k-line k-vertical" x1="0" y1="0" x2="0" y2="96" stroke="url(#primaryGrad192)" stroke-width="15" stroke-linecap="round" filter="url(#glow192)"></line>
|
||||
<line class="k-line k-diagonal-top" x1="0" y1="48" x2="57.6" y2="0" stroke="url(#primaryGrad192)" stroke-width="15" stroke-linecap="round" filter="url(#glow192)"></line>
|
||||
<line class="k-line k-diagonal-bottom" x1="0" y1="48" x2="57.6" y2="96" stroke="url(#primaryGrad192)" stroke-width="15" stroke-linecap="round" filter="url(#glow192)"></line>
|
||||
</g>
|
||||
|
||||
<!-- Animated status dot -->
|
||||
<circle class="status-dot" cx="163.2" cy="163.2" r="11.52" fill="#00DC82" opacity="0.9"></circle>
|
||||
<circle class="status-ring" cx="163.2" cy="163.2" r="17.28" fill="none" stroke="#00DC82" stroke-width="3" opacity="0.3"></circle>
|
||||
|
||||
<!-- Tech corners -->
|
||||
<line class="corner corner-tl-h" x1="15.36" y1="15.36" x2="28.8" y2="15.36" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
<line class="corner corner-tl-v" x1="15.36" y1="15.36" x2="15.36" y2="28.8" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
<line class="corner corner-tr-h" x1="176.64" y1="15.36" x2="163.2" y2="15.36" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
<line class="corner corner-tr-v" x1="176.64" y1="15.36" x2="176.64" y2="28.8" stroke="#00DC82" stroke-width="3" opacity="0.4"></line>
|
||||
</svg>
|
||||
|
||||
<!-- Ripple effect container -->
|
||||
<div class="ripple" v-if="showRipple"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
interface Props {
|
||||
size?: string
|
||||
interactive?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: '192px',
|
||||
interactive: true
|
||||
})
|
||||
|
||||
const iconSize = computed(() => props.size)
|
||||
const strokeWidth = computed(() => props.size / 32) // Scales with size
|
||||
const isClicked = ref(false)
|
||||
const showRipple = ref(false)
|
||||
|
||||
const handleClick = () => {
|
||||
if (!props.interactive) return
|
||||
|
||||
isClicked.value = true
|
||||
showRipple.value = true
|
||||
|
||||
setTimeout(() => {
|
||||
isClicked.value = false
|
||||
}, 600)
|
||||
|
||||
setTimeout(() => {
|
||||
showRipple.value = false
|
||||
}, 800)
|
||||
}
|
||||
|
||||
const handleHover = () => {
|
||||
if (!props.interactive) return
|
||||
// Hover animations are handled by CSS
|
||||
}
|
||||
|
||||
const handleLeave = () => {
|
||||
if (!props.interactive) return
|
||||
// Leave animations are handled by CSS
|
||||
}
|
||||
|
||||
const handleTouch = (e: TouchEvent) => {
|
||||
if (!props.interactive) return
|
||||
handleClick()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<svg
|
||||
:width="iconSize"
|
||||
:height="iconSize"
|
||||
:viewBox="`0 0 ${iconSize} ${iconSize}`"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<!-- Carbon fiber pattern -->
|
||||
<pattern
|
||||
id="carbon"
|
||||
x="0"
|
||||
y="0"
|
||||
:width="iconSize / 25"
|
||||
:height="iconSize / 25"
|
||||
patternUnits="userSpaceOnUse"
|
||||
>
|
||||
<rect :width="iconSize / 25" :height="iconSize / 25" fill="#0a0e27"/>
|
||||
<path
|
||||
:d="`M0,0 L${iconSize/50},${iconSize/50} M${iconSize/50},0 L${iconSize/25},${iconSize/50} M0,${iconSize/50} L${iconSize/50},${iconSize/25}`"
|
||||
stroke="#060815"
|
||||
:stroke-width="strokeWidth / 4"
|
||||
opacity="0.5"
|
||||
/>
|
||||
</pattern>
|
||||
<style scoped>
|
||||
.kompose-icon-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
<!-- Gradient for depth -->
|
||||
<linearGradient id="bgGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#1a1d2e;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#0a0e27;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
.kompose-icon-wrapper:not(.is-interactive) {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
<!-- Primary color gradient -->
|
||||
<linearGradient id="primaryGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#00DC82;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#00a86b;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
.kompose-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
filter: drop-shadow(0 4px 20px rgba(0, 220, 130, 0.2));
|
||||
transition: filter 0.4s ease;
|
||||
}
|
||||
|
||||
<!-- Glow effect -->
|
||||
<filter id="glow">
|
||||
<feGaussianBlur :stdDeviation="strokeWidth" result="coloredBlur"/>
|
||||
<feMerge>
|
||||
<feMergeNode in="coloredBlur"/>
|
||||
<feMergeNode in="SourceGraphic"/>
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
/* Hover Effects */
|
||||
.kompose-icon-wrapper.is-interactive:hover {
|
||||
transform: scale(1.05) translateY(-2px);
|
||||
}
|
||||
|
||||
<!-- Background with rounded corners -->
|
||||
<rect
|
||||
:width="iconSize"
|
||||
:height="iconSize"
|
||||
:rx="iconSize / 8"
|
||||
fill="url(#bgGrad)"
|
||||
/>
|
||||
|
||||
<!-- Carbon texture overlay -->
|
||||
<rect
|
||||
:width="iconSize"
|
||||
:height="iconSize"
|
||||
:rx="iconSize / 8"
|
||||
fill="url(#carbon)"
|
||||
opacity="0.4"
|
||||
/>
|
||||
.kompose-icon-wrapper.is-interactive:hover .kompose-icon {
|
||||
filter: drop-shadow(0 8px 30px rgba(0, 220, 130, 0.4));
|
||||
animation: subtle-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
<!-- Stylized "K" letter with geometric design -->
|
||||
<g :transform="`translate(${iconSize * 0.25}, ${iconSize * 0.25})`">
|
||||
<!-- Main vertical line of K -->
|
||||
<line
|
||||
:x1="0"
|
||||
:y1="0"
|
||||
:x2="0"
|
||||
:y2="iconSize * 0.5"
|
||||
stroke="url(#primaryGrad)"
|
||||
:stroke-width="strokeWidth * 2.5"
|
||||
stroke-linecap="round"
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
|
||||
<!-- Upper diagonal of K -->
|
||||
<line
|
||||
:x1="0"
|
||||
:y1="iconSize * 0.25"
|
||||
:x2="iconSize * 0.3"
|
||||
:y2="0"
|
||||
stroke="url(#primaryGrad)"
|
||||
:stroke-width="strokeWidth * 2.5"
|
||||
stroke-linecap="round"
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
|
||||
<!-- Lower diagonal of K -->
|
||||
<line
|
||||
:x1="0"
|
||||
:y1="iconSize * 0.25"
|
||||
:x2="iconSize * 0.3"
|
||||
:y2="iconSize * 0.5"
|
||||
stroke="url(#primaryGrad)"
|
||||
:stroke-width="strokeWidth * 2.5"
|
||||
stroke-linecap="round"
|
||||
filter="url(#glow)"
|
||||
/>
|
||||
</g>
|
||||
.kompose-icon-wrapper.is-interactive:hover .bg-rect {
|
||||
fill: url(#bgGrad192);
|
||||
opacity: 1;
|
||||
animation: bg-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
<!-- Animated status dot (bottom right) -->
|
||||
<circle
|
||||
:cx="iconSize * 0.85"
|
||||
:cy="iconSize * 0.85"
|
||||
:r="iconSize * 0.06"
|
||||
fill="#00DC82"
|
||||
opacity="0.9"
|
||||
>
|
||||
<animate
|
||||
attributeName="opacity"
|
||||
values="0.6;1;0.6"
|
||||
dur="2s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
<animate
|
||||
attributeName="r"
|
||||
:values="`${iconSize * 0.06};${iconSize * 0.07};${iconSize * 0.06}`"
|
||||
dur="2s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</circle>
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-letter {
|
||||
animation: letter-glow 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
<!-- Glow ring around dot -->
|
||||
<circle
|
||||
:cx="iconSize * 0.85"
|
||||
:cy="iconSize * 0.85"
|
||||
:r="iconSize * 0.09"
|
||||
fill="none"
|
||||
stroke="#00DC82"
|
||||
:stroke-width="strokeWidth / 2"
|
||||
opacity="0.3"
|
||||
/>
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-vertical {
|
||||
animation: line-slide-vertical 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
<!-- Tech corner accents -->
|
||||
<line
|
||||
:x1="iconSize * 0.08"
|
||||
:y1="iconSize * 0.08"
|
||||
:x2="iconSize * 0.15"
|
||||
:y2="iconSize * 0.08"
|
||||
stroke="#00DC82"
|
||||
:stroke-width="strokeWidth / 2"
|
||||
opacity="0.4"
|
||||
/>
|
||||
<line
|
||||
:x1="iconSize * 0.08"
|
||||
:y1="iconSize * 0.08"
|
||||
:x2="iconSize * 0.08"
|
||||
:y2="iconSize * 0.15"
|
||||
stroke="#00DC82"
|
||||
:stroke-width="strokeWidth / 2"
|
||||
opacity="0.4"
|
||||
/>
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-diagonal-top {
|
||||
animation: line-slide-diagonal-top 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) 0.1s;
|
||||
}
|
||||
|
||||
<line
|
||||
:x1="iconSize * 0.92"
|
||||
:y1="iconSize * 0.08"
|
||||
:x2="iconSize * 0.85"
|
||||
:y2="iconSize * 0.08"
|
||||
stroke="#00DC82"
|
||||
:stroke-width="strokeWidth / 2"
|
||||
opacity="0.4"
|
||||
/>
|
||||
<line
|
||||
:x1="iconSize * 0.92"
|
||||
:y1="iconSize * 0.08"
|
||||
:x2="iconSize * 0.92"
|
||||
:y2="iconSize * 0.15"
|
||||
stroke="#00DC82"
|
||||
:stroke-width="strokeWidth / 2"
|
||||
opacity="0.4"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
.kompose-icon-wrapper.is-interactive:hover .k-diagonal-bottom {
|
||||
animation: line-slide-diagonal-bottom 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) 0.2s;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .status-dot {
|
||||
animation: pulse-expand 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .status-ring {
|
||||
animation: ring-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover .corner {
|
||||
opacity: 1 !important;
|
||||
stroke: #00DC82;
|
||||
animation: corner-extend 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
/* Click/Active Effects */
|
||||
.kompose-icon-wrapper.is-clicked {
|
||||
animation: click-bounce 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-clicked .kompose-icon {
|
||||
animation: rotate-3d 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
filter: drop-shadow(0 12px 40px rgba(0, 220, 130, 0.6));
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-clicked .k-letter {
|
||||
animation: letter-flash 0.6s ease-out;
|
||||
filter: url(#intenseglow192);
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-clicked .status-dot {
|
||||
animation: dot-burst 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* Ripple Effect */
|
||||
.ripple {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(0, 220, 130, 0.6) 0%, rgba(0, 220, 130, 0) 70%);
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
animation: ripple-expand 0.8s ease-out;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Default animations for status dot */
|
||||
.status-dot {
|
||||
animation: default-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.status-ring {
|
||||
animation: default-ring-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Keyframe Animations */
|
||||
@keyframes subtle-pulse {
|
||||
0%, 100% {
|
||||
filter: drop-shadow(0 8px 30px rgba(0, 220, 130, 0.4));
|
||||
}
|
||||
50% {
|
||||
filter: drop-shadow(0 8px 35px rgba(0, 220, 130, 0.6));
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bg-glow {
|
||||
0%, 100% {
|
||||
filter: brightness(1);
|
||||
}
|
||||
50% {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes letter-glow {
|
||||
0%, 100% {
|
||||
filter: url(#glow192);
|
||||
}
|
||||
50% {
|
||||
filter: url(#intenseglow192);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes line-slide-vertical {
|
||||
0% {
|
||||
stroke-dasharray: 96;
|
||||
stroke-dashoffset: 96;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 96;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes line-slide-diagonal-top {
|
||||
0% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 68;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes line-slide-diagonal-bottom {
|
||||
0% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 68;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 68;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse-expand {
|
||||
0%, 100% {
|
||||
r: 11.52;
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
r: 14;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ring-pulse {
|
||||
0%, 100% {
|
||||
r: 17.28;
|
||||
opacity: 0.3;
|
||||
stroke-width: 3;
|
||||
}
|
||||
50% {
|
||||
r: 20;
|
||||
opacity: 0.6;
|
||||
stroke-width: 2;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes corner-extend {
|
||||
0% {
|
||||
stroke-dasharray: 13.44;
|
||||
stroke-dashoffset: 13.44;
|
||||
}
|
||||
100% {
|
||||
stroke-dasharray: 13.44;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes click-bounce {
|
||||
0% {
|
||||
transform: scale(1) translateY(0) rotateY(0deg);
|
||||
}
|
||||
30% {
|
||||
transform: scale(0.92) translateY(0) rotateY(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.08) translateY(-4px) rotateY(180deg);
|
||||
}
|
||||
70% {
|
||||
transform: scale(0.98) translateY(0) rotateY(360deg);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1) translateY(0) rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate-3d {
|
||||
0% {
|
||||
transform: perspective(800px) rotateY(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: perspective(800px) rotateY(180deg);
|
||||
}
|
||||
100% {
|
||||
transform: perspective(800px) rotateY(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes letter-flash {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
20%, 60% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
40%, 80% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dot-burst {
|
||||
0% {
|
||||
r: 11.52;
|
||||
opacity: 0.9;
|
||||
}
|
||||
50% {
|
||||
r: 20;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
r: 11.52;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes ripple-expand {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(2.5);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes default-pulse {
|
||||
0%, 100% {
|
||||
opacity: 0.6;
|
||||
r: 11.52;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
r: 13.44;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes default-ring-pulse {
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.kompose-icon-wrapper.is-interactive:hover {
|
||||
transform: scale(1.03) translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduced motion support */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.kompose-icon-wrapper,
|
||||
.kompose-icon,
|
||||
.kompose-icon *,
|
||||
.ripple {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
.kompose-icon-wrapper.is-interactive:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch device optimizations */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.kompose-icon-wrapper.is-interactive:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
0
Projects/kompose/docs/app/components/AppIconShowcase.vue
Normal file → Executable file
0
Projects/kompose/docs/app/components/AppLogo.vue
Normal file → Executable file
0
Projects/kompose/docs/app/components/OgImage/OgImageDocs.vue
Normal file → Executable file
0
Projects/kompose/docs/app/components/PageHeaderLinks.vue
Normal file → Executable file
24
Projects/kompose/docs/app/components/TemplateMenu.vue
Normal file → Executable file
@@ -3,11 +3,11 @@
|
||||
v-slot="{ open }"
|
||||
:modal="false"
|
||||
:items="[{
|
||||
label: 'Starter',
|
||||
to: 'https://starter-template.nuxt.dev/'
|
||||
label: 'Blog',
|
||||
to: 'https://pivoine.art'
|
||||
}, {
|
||||
label: 'Landing',
|
||||
to: 'https://landing-template.nuxt.dev/'
|
||||
label: 'Code',
|
||||
to: 'https://code.pivoine.art'
|
||||
}, {
|
||||
label: 'Docs',
|
||||
to: 'https://docs-template.nuxt.dev/',
|
||||
@@ -15,20 +15,8 @@
|
||||
checked: true,
|
||||
type: 'checkbox'
|
||||
}, {
|
||||
label: 'SaaS',
|
||||
to: 'https://saas-template.nuxt.dev/'
|
||||
}, {
|
||||
label: 'Dashboard',
|
||||
to: 'https://dashboard-template.nuxt.dev/'
|
||||
}, {
|
||||
label: 'Chat',
|
||||
to: 'https://chat-template.nuxt.dev/'
|
||||
}, {
|
||||
label: 'Portfolio',
|
||||
to: 'https://portfolio-template.nuxt.dev/'
|
||||
}, {
|
||||
label: 'Changelog',
|
||||
to: 'https://changelog-template.nuxt.dev/'
|
||||
label: 'Sexy',
|
||||
to: 'https://sexy.pivoine.art'
|
||||
}]"
|
||||
:content="{ align: 'start' }"
|
||||
:ui="{ content: 'min-w-fit' }"
|
||||
|
||||
0
Projects/kompose/docs/app/components/content/HeroBackground.vue
Normal file → Executable file
0
Projects/kompose/docs/app/components/content/StarsBg.vue
Normal file → Executable file
0
Projects/kompose/docs/app/error.vue
Normal file → Executable file
0
Projects/kompose/docs/app/layouts/docs.vue
Normal file → Executable file
0
Projects/kompose/docs/app/pages/[...slug].vue
Normal file → Executable file
0
Projects/kompose/docs/compose.yaml
Normal file → Executable file
0
Projects/kompose/docs/content.config.ts
Normal file → Executable file
0
Projects/kompose/docs/content/1.index.md
Normal file → Executable file
0
Projects/kompose/docs/content/2.installation.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/configuration.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/database.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/hooks.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/index.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/network.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/quick-start.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/stack-management.md
Normal file → Executable file
0
Projects/kompose/docs/content/3.guide/troubleshooting.md
Normal file → Executable file
0
Projects/kompose/docs/content/4.reference/cli.md
Normal file → Executable file
0
Projects/kompose/docs/content/4.reference/environment.md
Normal file → Executable file
0
Projects/kompose/docs/content/4.reference/index.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/auth.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/auto.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/blog.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/chain.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/chat.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/code.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/dash.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/data.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/dock.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/home.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/index.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/link.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/news.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/proxy.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/sexy.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/trace.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/track.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/vault.md
Normal file → Executable file
0
Projects/kompose/docs/content/5.stacks/vpn.md
Normal file → Executable file
0
Projects/kompose/docs/eslint.config.mjs
Normal file → Executable file
0
Projects/kompose/docs/nuxt.config.ts
Normal file → Executable file
0
Projects/kompose/docs/package.json
Normal file → Executable file
0
Projects/kompose/docs/pnpm-lock.yaml
generated
Normal file → Executable file
0
Projects/kompose/docs/pnpm-workspace.yaml
Normal file → Executable file
0
Projects/kompose/docs/public/apple-touch-icon.png
Normal file → Executable file
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
0
Projects/kompose/docs/public/favicon-96x96.png
Normal file → Executable file
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
0
Projects/kompose/docs/public/favicon.ico
Normal file → Executable file
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
Projects/kompose/docs/public/favicon.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
0
Projects/kompose/docs/public/icon.svg
Normal file → Executable file
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
0
Projects/kompose/docs/public/web-app-manifest-192x192.png
Normal file → Executable file
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
0
Projects/kompose/docs/public/web-app-manifest-512x512.png
Normal file → Executable file
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |