اپ: نام برند در همهی صفحهها و پیامها یکسان شده و از یک تنظیم مرکزی خوانده میشود. اپ: کارت حسابداری در صفحهی مشتری بازطراحی شد؛ ماندهها و وضعیت لینک واضحتر نمایش داده میشوند. پنل: کارت حسابداری در پروندهی مشتری بازطراحی شد؛ ماندهها، آخرین ارسال و فرم لینک دستی واضحتر شدهاند. پنل: ستون «کد» در جدولها بهطور پیشفرض پنهان است و از انتخاب ستونها قابل نمایش است. پنل: تغییر نمایش ستونها در جدولها بلافاصله اعمال میشود. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
331 lines
12 KiB
Vue
331 lines
12 KiB
Vue
<!--
|
|
Inline, animated illustrations for IslandSheet — one per job the sheet does,
|
|
so the picture says what the action is before the text does:
|
|
|
|
logout — a door swung open with an arrow walking out of it
|
|
login — a phone showing a sign-in form, with a lock badge easing open
|
|
order — a gold shopping bag that a coin keeps dropping into, ticked
|
|
update — a rocket lifting off (a new version "launched")
|
|
success — the uploaded documents, stamped with a green check
|
|
|
|
Inline SVG rather than image files so they can animate, pick up the
|
|
sheet's tone, and cost no network request (the update dialog used to pull
|
|
a Lottie file from a third-party host on every launch).
|
|
|
|
Gradient/clip ids go through useId(): several sheets can be mounted on one
|
|
page, and a duplicate id would resolve to the first copy in the document —
|
|
which, inside a hidden sheet, renders as nothing.
|
|
|
|
The one-off entrance animations (badge pop, check drawing) replay every
|
|
time the sheet opens, because the sheet hides with display:none and CSS
|
|
animations restart when an element is displayed again.
|
|
-->
|
|
<template>
|
|
<svg class="sa" :class="`sa--${name}`" viewBox="0 0 120 120" fill="none" aria-hidden="true">
|
|
<!-- logout -->
|
|
<template v-if="name === 'logout'">
|
|
<defs>
|
|
<linearGradient :id="ids.a" x1="0" y1="0" x2="1" y2="1">
|
|
<stop offset="0" stop-color="#A0386A" />
|
|
<stop offset="1" stop-color="#5A0027" />
|
|
</linearGradient>
|
|
<radialGradient :id="ids.b" cx=".35" cy=".5" r=".75">
|
|
<stop offset="0" stop-color="#FFF7E6" />
|
|
<stop offset="1" stop-color="#F4C57A" />
|
|
</radialGradient>
|
|
</defs>
|
|
<ellipse class="sa-shadow" cx="62" cy="106" rx="36" ry="4" fill="#7C0035" opacity=".12" />
|
|
<rect x="48" y="18" width="40" height="84" rx="5" :fill="`url(#${ids.b})`" stroke="#7C0035" stroke-width="3" />
|
|
<g class="sa-door">
|
|
<path d="M88 18 L88 102 L69 108 L69 12 Z" :fill="`url(#${ids.a})`" stroke="#5A0027" stroke-width="2" stroke-linejoin="round" />
|
|
<circle cx="73.5" cy="61" r="2.6" fill="#F4C57A" />
|
|
</g>
|
|
<g class="sa-arrow" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M60 60 H22 M33 48 L21 60 L33 72" stroke="#fff" stroke-width="12" />
|
|
<path d="M60 60 H22 M33 48 L21 60 L33 72" stroke="#7C0035" stroke-width="6" />
|
|
</g>
|
|
</template>
|
|
|
|
<!-- login -->
|
|
<template v-else-if="name === 'login'">
|
|
<ellipse class="sa-shadow" cx="60" cy="110" rx="28" ry="4" fill="#1C2D56" opacity=".12" />
|
|
<g class="sa-float">
|
|
<rect x="34" y="10" width="52" height="92" rx="12" fill="#1C2D56" />
|
|
<rect x="38" y="14" width="44" height="84" rx="9" fill="#fff" />
|
|
<rect x="52" y="18.5" width="16" height="4" rx="2" fill="#1C2D56" opacity=".85" />
|
|
<circle cx="60" cy="42" r="12" fill="#E3E8F4" />
|
|
<circle cx="60" cy="39" r="4.6" fill="#1C2D56" />
|
|
<path d="M51.5 51 a8.5 6.5 0 0 1 17 0 Z" fill="#1C2D56" />
|
|
<rect x="44" y="62" width="32" height="6" rx="3" fill="#ECEDEF" />
|
|
<rect class="sa-typing" x="44" y="62" width="22" height="6" rx="3" fill="#CACED8" />
|
|
<rect x="44" y="74" width="32" height="10" rx="5" fill="#1C2D56" />
|
|
</g>
|
|
<g class="sa-pop">
|
|
<circle cx="85" cy="86" r="15" fill="#D9A441" stroke="#fff" stroke-width="3" />
|
|
<path class="sa-shackle" d="M80 85 v-3.4 a4 4 0 0 1 8 0 V85" stroke="#fff" stroke-width="2.4" stroke-linecap="round" />
|
|
<rect x="77.5" y="84.5" width="15" height="10.5" rx="2.6" fill="#fff" />
|
|
<circle cx="85" cy="89.8" r="1.7" fill="#D9A441" />
|
|
</g>
|
|
</template>
|
|
|
|
<!-- order -->
|
|
<template v-else-if="name === 'order'">
|
|
<defs>
|
|
<linearGradient :id="ids.a" x1="0" y1="0" x2="0" y2="1">
|
|
<stop offset="0" stop-color="#EBC06A" />
|
|
<stop offset="1" stop-color="#B5843B" />
|
|
</linearGradient>
|
|
<radialGradient :id="ids.b" cx=".38" cy=".35" r=".7">
|
|
<stop offset="0" stop-color="#FFF1C7" />
|
|
<stop offset="1" stop-color="#E2AC4A" />
|
|
</radialGradient>
|
|
</defs>
|
|
<ellipse class="sa-shadow" cx="60" cy="108" rx="32" ry="4" fill="#8D6A46" opacity=".16" />
|
|
<path d="M46 57 V40 a14 14 0 0 1 28 0 V57" stroke="#8D6A46" stroke-width="4.5" stroke-linecap="round" />
|
|
<g class="sa-coin">
|
|
<circle cx="60" cy="31" r="10" :fill="`url(#${ids.b})`" stroke="#B5843B" stroke-width="2" />
|
|
<circle cx="60" cy="31" r="5.5" stroke="#B5843B" stroke-width="1.5" opacity=".7" />
|
|
</g>
|
|
<path d="M30 48 H90 L85 100 a6 6 0 0 1 -6 5.5 H41 a6 6 0 0 1 -6 -5.5 Z" :fill="`url(#${ids.a})`" />
|
|
<path d="M30 48 H90 L89.4 54.5 H30.6 Z" fill="#8D6A46" opacity=".28" />
|
|
<path d="M37 60 L39.5 96" stroke="#fff" stroke-width="3" stroke-linecap="round" opacity=".35" />
|
|
<circle cx="46" cy="57" r="2.4" fill="#8D6A46" />
|
|
<circle cx="74" cy="57" r="2.4" fill="#8D6A46" />
|
|
<g class="sa-pop">
|
|
<circle cx="60" cy="80" r="13" fill="#fff" />
|
|
<path class="sa-draw" d="M54 80.5 l4.2 4.2 L66.5 76" stroke="#16a34a" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round" />
|
|
</g>
|
|
</template>
|
|
|
|
<!-- update -->
|
|
<template v-else-if="name === 'update'">
|
|
<defs>
|
|
<linearGradient :id="ids.a" x1="0" y1="0" x2="0" y2="1">
|
|
<stop offset="0" stop-color="#FFD27A" />
|
|
<stop offset="1" stop-color="#F2793B" />
|
|
</linearGradient>
|
|
<clipPath :id="ids.b">
|
|
<path d="M60 10 C76 22 80 44 76 72 H44 C40 44 44 22 60 10 Z" />
|
|
</clipPath>
|
|
</defs>
|
|
<g stroke="#CACED8" stroke-width="3" stroke-linecap="round">
|
|
<path class="sa-trail" d="M28 28 v14" />
|
|
<path class="sa-trail sa-trail--2" d="M94 40 v12" />
|
|
<path class="sa-trail sa-trail--3" d="M22 64 v10" />
|
|
<path class="sa-trail sa-trail--4" d="M99 70 v12" />
|
|
</g>
|
|
<g class="sa-float">
|
|
<g class="sa-flame">
|
|
<path d="M51 77 Q60 112 69 77 Z" :fill="`url(#${ids.a})`" />
|
|
<path d="M55.5 77 Q60 96 64.5 77 Z" fill="#FFF1C9" />
|
|
</g>
|
|
<path d="M44 56 L31 76 Q31 80 35 79 L46 74 Z" fill="#D9A441" />
|
|
<path d="M76 56 L89 76 Q89 80 85 79 L74 74 Z" fill="#D9A441" />
|
|
<path d="M60 10 C76 22 80 44 76 72 H44 C40 44 44 22 60 10 Z" fill="#fff" />
|
|
<g :clip-path="`url(#${ids.b})`">
|
|
<rect x="30" y="0" width="60" height="31" fill="#1C2D56" />
|
|
<rect x="30" y="64" width="60" height="10" fill="#E3E8F4" />
|
|
</g>
|
|
<path d="M60 10 C76 22 80 44 76 72 H44 C40 44 44 22 60 10 Z" stroke="#1C2D56" stroke-width="3" stroke-linejoin="round" />
|
|
<circle cx="60" cy="46" r="7.5" fill="#DCE5F7" stroke="#1C2D56" stroke-width="3" />
|
|
<circle cx="57.6" cy="43.6" r="2" fill="#fff" />
|
|
<rect x="49" y="71" width="22" height="7" rx="2.5" fill="#1C2D56" />
|
|
</g>
|
|
</template>
|
|
|
|
<!-- success -->
|
|
<template v-else-if="name === 'success'">
|
|
<ellipse class="sa-shadow" cx="58" cy="108" rx="32" ry="4" fill="#16a34a" opacity=".14" />
|
|
<rect x="26" y="24" width="50" height="70" rx="8" fill="#D6F0DF" transform="rotate(-9 51 59)" />
|
|
<rect x="34" y="16" width="50" height="72" rx="8" fill="#fff" stroke="#1f7a45" stroke-width="2.5" />
|
|
<circle cx="46" cy="31" r="6" fill="#BFE8CD" />
|
|
<rect x="56" y="27" width="20" height="4" rx="2" fill="#E1EFE6" />
|
|
<rect x="56" y="34" width="13" height="4" rx="2" fill="#E1EFE6" />
|
|
<rect x="42" y="48" width="34" height="4" rx="2" fill="#E1EFE6" />
|
|
<rect x="42" y="56" width="27" height="4" rx="2" fill="#E1EFE6" />
|
|
<rect x="42" y="64" width="31" height="4" rx="2" fill="#E1EFE6" />
|
|
<circle class="sa-ring" cx="84" cy="85" r="17" fill="#16a34a" />
|
|
<g class="sa-pop">
|
|
<circle cx="84" cy="85" r="17" fill="#16a34a" stroke="#fff" stroke-width="3" />
|
|
<path class="sa-draw" d="M76.5 85.5 l5 5 L92 80" stroke="#fff" stroke-width="3.6" stroke-linecap="round" stroke-linejoin="round" />
|
|
</g>
|
|
<g class="sa-confetti">
|
|
<rect x="18" y="30" width="6" height="6" rx="1.5" fill="#F4C57A" transform="rotate(20 21 33)" />
|
|
<circle cx="98" cy="26" r="3.2" fill="#16a34a" />
|
|
<rect x="100" y="52" width="7" height="3.5" rx="1.75" fill="#A0386A" transform="rotate(-30 103.5 53.75)" />
|
|
<circle cx="20" cy="72" r="2.6" fill="#335CB1" />
|
|
<rect x="88" y="8" width="3.5" height="7" rx="1.75" fill="#D9A441" transform="rotate(35 89.75 11.5)" />
|
|
</g>
|
|
</template>
|
|
</svg>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useId } from 'vue'
|
|
|
|
export type SheetArtName = 'logout' | 'login' | 'order' | 'update' | 'success'
|
|
|
|
defineProps<{ name: SheetArtName }>()
|
|
|
|
const uid = useId()
|
|
const ids = { a: `${uid}-a`, b: `${uid}-b` }
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.sa {
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: visible;
|
|
}
|
|
|
|
// Everything that moves scales/rotates about its own box, not the SVG origin.
|
|
.sa * {
|
|
transform-box: fill-box;
|
|
transform-origin: center;
|
|
}
|
|
|
|
// Entrances (once per open)
|
|
.sa-pop {
|
|
animation: sa-pop 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) 0.25s both;
|
|
}
|
|
|
|
.sa-draw {
|
|
stroke-dasharray: 30;
|
|
stroke-dashoffset: 30;
|
|
animation: sa-draw 0.45s ease-out 0.6s forwards;
|
|
}
|
|
|
|
// Loops
|
|
.sa-shadow {
|
|
animation: sa-shadow 3.2s ease-in-out infinite;
|
|
}
|
|
|
|
.sa-float {
|
|
animation: sa-float 3.2s ease-in-out infinite;
|
|
}
|
|
|
|
.sa-door {
|
|
transform-origin: right center;
|
|
animation: sa-door 2.8s ease-in-out infinite;
|
|
}
|
|
|
|
.sa-arrow {
|
|
animation: sa-nudge 2.8s ease-in-out infinite;
|
|
}
|
|
|
|
.sa-typing {
|
|
transform-origin: right center; // the form is RTL — text grows from the right
|
|
animation: sa-typing 2.6s ease-in-out infinite;
|
|
}
|
|
|
|
.sa-shackle {
|
|
animation: sa-shackle 2.6s ease-in-out 0.9s infinite;
|
|
}
|
|
|
|
.sa-coin {
|
|
animation: sa-coin 2.4s cubic-bezier(0.55, 0, 0.75, 0.4) 0.4s infinite backwards;
|
|
}
|
|
|
|
.sa-flame {
|
|
transform-origin: center top;
|
|
animation: sa-flame 0.22s ease-in-out infinite alternate;
|
|
}
|
|
|
|
.sa-trail {
|
|
animation: sa-trail 1.1s linear infinite;
|
|
|
|
&--2 { animation-delay: 0.35s; }
|
|
&--3 { animation-delay: 0.6s; }
|
|
&--4 { animation-delay: 0.85s; }
|
|
}
|
|
|
|
.sa-ring {
|
|
animation: sa-ring 2s ease-out 0.8s infinite;
|
|
opacity: 0;
|
|
}
|
|
|
|
.sa-confetti > * {
|
|
animation: sa-confetti 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) both;
|
|
|
|
&:nth-child(1) { animation-delay: 0.7s; }
|
|
&:nth-child(2) { animation-delay: 0.78s; }
|
|
&:nth-child(3) { animation-delay: 0.86s; }
|
|
&:nth-child(4) { animation-delay: 0.94s; }
|
|
&:nth-child(5) { animation-delay: 1.02s; }
|
|
}
|
|
|
|
@keyframes sa-pop {
|
|
from { transform: scale(0); }
|
|
to { transform: scale(1); }
|
|
}
|
|
|
|
@keyframes sa-draw {
|
|
to { stroke-dashoffset: 0; }
|
|
}
|
|
|
|
@keyframes sa-shadow {
|
|
50% { transform: scaleX(0.82); opacity: 0.08; }
|
|
}
|
|
|
|
@keyframes sa-float {
|
|
50% { transform: translateY(-4px); }
|
|
}
|
|
|
|
@keyframes sa-door {
|
|
0%, 100% { transform: scaleX(1); }
|
|
50% { transform: scaleX(0.72); }
|
|
}
|
|
|
|
@keyframes sa-nudge {
|
|
0%, 100% { transform: translateX(0); }
|
|
50% { transform: translateX(-6px); }
|
|
}
|
|
|
|
@keyframes sa-typing {
|
|
0% { transform: scaleX(0.15); }
|
|
60%, 100% { transform: scaleX(1); }
|
|
}
|
|
|
|
@keyframes sa-shackle {
|
|
0%, 55%, 100% { transform: translateY(0); }
|
|
20%, 40% { transform: translateY(-3px); }
|
|
}
|
|
|
|
@keyframes sa-coin {
|
|
0% { transform: translateY(-24px); opacity: 0; }
|
|
20% { opacity: 1; }
|
|
100% { transform: translateY(26px); opacity: 1; }
|
|
}
|
|
|
|
@keyframes sa-flame {
|
|
from { transform: scaleY(0.82) scaleX(0.94); }
|
|
to { transform: scaleY(1.12) scaleX(1.04); }
|
|
}
|
|
|
|
@keyframes sa-trail {
|
|
from { transform: translateY(-8px); opacity: 0; }
|
|
30% { opacity: 1; }
|
|
to { transform: translateY(22px); opacity: 0; }
|
|
}
|
|
|
|
@keyframes sa-ring {
|
|
from { transform: scale(1); opacity: 0.35; }
|
|
to { transform: scale(1.7); opacity: 0; }
|
|
}
|
|
|
|
@keyframes sa-confetti {
|
|
from { transform: scale(0) translateY(6px); opacity: 0; }
|
|
to { transform: scale(1) translateY(0); opacity: 1; }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.sa * {
|
|
animation: none !important;
|
|
}
|
|
|
|
.sa-draw {
|
|
stroke-dashoffset: 0;
|
|
}
|
|
}
|
|
</style>
|