|
7 | 7 | target="_blank" |
8 | 8 | rel="noreferrer" |
9 | 9 | > |
10 | | - <span><slot /></span> |
11 | | - <span v-if="arrow" class="btn-arrow" aria-hidden="true">→</span> |
| 10 | + <span class="btn__label"><slot /></span> |
| 11 | + <span v-if="arrow" class="btn__arrow" aria-hidden="true">→</span> |
12 | 12 | </a> |
13 | | - |
14 | 13 | <RouterLink v-else class="btn" :class="[`btn--${variant}`]" :to="href"> |
15 | | - <span><slot /></span> |
16 | | - <span v-if="arrow" class="btn-arrow" aria-hidden="true">→</span> |
| 14 | + <span class="btn__label"><slot /></span> |
| 15 | + <span v-if="arrow" class="btn__arrow" aria-hidden="true">→</span> |
17 | 16 | </RouterLink> |
18 | 17 | </template> |
19 | 18 |
|
20 | 19 | <script setup> |
21 | 20 | import { computed } from "vue"; |
22 | 21 |
|
23 | 22 | const props = defineProps({ |
24 | | - href: { |
25 | | - type: String, |
26 | | - required: true, |
27 | | - }, |
| 23 | + href: { type: String, required: true }, |
28 | 24 | variant: { |
29 | 25 | type: String, |
30 | 26 | default: "primary", |
31 | | - validator: (value) => ["primary", "secondary", "ghost"].includes(value), |
32 | | - }, |
33 | | - external: { |
34 | | - type: Boolean, |
35 | | - default: false, |
36 | | - }, |
37 | | - arrow: { |
38 | | - type: Boolean, |
39 | | - default: false, |
| 27 | + validator: (v) => ["primary", "secondary", "ghost"].includes(v), |
40 | 28 | }, |
| 29 | + external: { type: Boolean, default: false }, |
| 30 | + arrow: { type: Boolean, default: false }, |
41 | 31 | }); |
42 | 32 |
|
43 | | -const isExternalHref = computed(() => { |
44 | | - return props.href.startsWith("http://") || props.href.startsWith("https://"); |
45 | | -}); |
| 33 | +const isExternalHref = computed( |
| 34 | + () => props.href.startsWith("http://") || props.href.startsWith("https://"), |
| 35 | +); |
46 | 36 | </script> |
47 | 37 |
|
48 | 38 | <style scoped> |
49 | 39 | .btn { |
50 | 40 | display: inline-flex; |
51 | 41 | align-items: center; |
52 | | - justify-content: center; |
53 | | - gap: 0.55rem; |
54 | | - min-height: 44px; |
55 | | - padding: 0.72rem 1rem; |
56 | | - border-radius: 999px; |
57 | | - font-size: 0.9rem; |
58 | | - font-weight: 750; |
59 | | - line-height: 1; |
| 42 | + gap: 0.5rem; |
| 43 | + padding: 0.7rem 1.2rem; |
| 44 | + border-radius: var(--radius-md); |
| 45 | + font-size: 0.92rem; |
| 46 | + font-weight: 600; |
| 47 | + letter-spacing: -0.01em; |
60 | 48 | text-decoration: none; |
| 49 | + border: 1px solid transparent; |
61 | 50 | transition: |
62 | | - transform var(--speed) var(--ease), |
63 | | - border-color var(--speed) var(--ease), |
64 | 51 | background var(--speed) var(--ease), |
65 | | - color var(--speed) var(--ease); |
66 | | -} |
67 | | -
|
68 | | -.btn:hover { |
69 | | - transform: translateY(-1px); |
| 52 | + border-color var(--speed) var(--ease), |
| 53 | + color var(--speed) var(--ease), |
| 54 | + transform var(--speed) var(--ease), |
| 55 | + box-shadow var(--speed) var(--ease); |
70 | 56 | } |
71 | 57 |
|
| 58 | +/* Primary — solid green */ |
72 | 59 | .btn--primary { |
73 | | - border: 1px solid rgba(34, 197, 94, 0.55); |
74 | | - background: linear-gradient(180deg, #35d56d, #16a34a); |
75 | | - color: #031108; |
76 | | - box-shadow: 0 12px 36px rgba(34, 197, 94, 0.18); |
| 60 | + background: var(--green); |
| 61 | + color: #fff; |
| 62 | + box-shadow: var(--shadow-green); |
77 | 63 | } |
78 | | -
|
79 | 64 | .btn--primary:hover { |
80 | | - color: #031108; |
81 | | - border-color: rgba(167, 243, 208, 0.85); |
| 65 | + background: var(--green-strong); |
| 66 | + color: #fff; |
| 67 | + transform: translateY(-1px); |
82 | 68 | } |
83 | 69 |
|
| 70 | +/* Secondary — outlined */ |
84 | 71 | .btn--secondary { |
85 | | - border: 1px solid rgba(34, 197, 94, 0.22); |
86 | | - background: rgba(34, 197, 94, 0.08); |
87 | | - color: var(--green-soft); |
| 72 | + background: var(--bg-panel); |
| 73 | + border-color: var(--line-strong); |
| 74 | + color: var(--text); |
88 | 75 | } |
89 | | -
|
90 | 76 | .btn--secondary:hover { |
91 | | - border-color: rgba(34, 197, 94, 0.42); |
92 | | - background: rgba(34, 197, 94, 0.12); |
93 | | - color: #bbf7d0; |
| 77 | + border-color: var(--green-line); |
| 78 | + color: var(--green-strong); |
| 79 | + transform: translateY(-1px); |
94 | 80 | } |
95 | 81 |
|
| 82 | +/* Ghost — bare */ |
96 | 83 | .btn--ghost { |
97 | | - border: 1px solid var(--line); |
98 | | - background: rgba(255, 255, 255, 0.025); |
| 84 | + background: transparent; |
| 85 | + border-color: transparent; |
99 | 86 | color: var(--text-soft); |
100 | 87 | } |
101 | | -
|
102 | 88 | .btn--ghost:hover { |
103 | | - border-color: rgba(148, 163, 184, 0.22); |
104 | | - background: rgba(255, 255, 255, 0.045); |
| 89 | + background: var(--bg-sunken); |
105 | 90 | color: var(--text); |
106 | 91 | } |
107 | 92 |
|
108 | | -.btn-arrow { |
109 | | - transform: translateY(-0.5px); |
110 | | - opacity: 0.85; |
| 93 | +.btn__arrow { |
| 94 | + opacity: 0.75; |
| 95 | + transition: transform var(--speed) var(--ease); |
| 96 | +} |
| 97 | +.btn:hover .btn__arrow { |
| 98 | + transform: translateX(2px); |
111 | 99 | } |
112 | 100 | </style> |
0 commit comments