Skip to content

Commit 74c044a

Browse files
momoclaude
authored andcommitted
Fix README URLs and polish LicenseSelector UI
- Update 16 license README links across index.md and using-modelgo-licenses.md (MG0-2.0.txt → v2/MG0/LICENSE) - LicenseSelector.vue: add hint text, animated selection border, improved responsive layout, and visual refinements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e03b25c commit 74c044a

3 files changed

Lines changed: 175 additions & 86 deletions

File tree

docs/.vitepress/components/LicenseSelector.vue

Lines changed: 159 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ const licenses = Object.keys(licenseMap)
4545
const selected = ref<string | null>(null)
4646
const downloading = ref(false)
4747
48-
// Only the visible badges — TransitionGroup handles enter/leave/move
4948
const visibleBadges = computed(() => {
5049
if (!selected.value) return allBadges
5150
const keys = new Set(licenseMap[selected.value])
@@ -81,72 +80,168 @@ async function downloadLicense() {
8180

8281
<template>
8382
<div class="ls-root">
84-
<p class="ls-hint">👇 Click a license to explore</p>
85-
86-
<div class="ls-buttons">
87-
<button
88-
v-for="name in licenses"
89-
:key="name"
90-
:class="['ls-btn', { active: selected === name }]"
91-
@click="selectLicense(name)"
92-
>
93-
{{ name }}
94-
</button>
83+
<!-- Fixed-height slot for hint so nothing shifts -->
84+
<div class="ls-hint-slot">
85+
<Transition name="hint">
86+
<p v-if="!selected" class="ls-hint">
87+
Pick Your License <span class="hint-arrow">↓</span>
88+
</p>
89+
</Transition>
9590
</div>
9691

97-
<div class="ls-badges-wrap">
98-
<TransitionGroup name="badge" tag="div" class="ls-badges">
99-
<div
100-
v-for="b in visibleBadges"
101-
:key="b.key"
102-
class="ls-badge"
103-
:style="{ '--badge-color': b.color }"
92+
<!-- Buttons area with optional animated border -->
93+
<div class="ls-buttons-area">
94+
<!-- Rotating border overlay -->
95+
<Transition name="box-fade">
96+
<div v-if="!selected" class="ls-border-ring" aria-hidden="true" />
97+
</Transition>
98+
99+
<div class="ls-buttons">
100+
<button
101+
v-for="name in licenses"
102+
:key="name"
103+
:class="['ls-btn', { active: selected === name }]"
104+
@click="selectLicense(name)"
104105
>
105-
<span class="badge-icon">{{ b.icon }}</span>
106-
<div class="badge-text">
107-
<span class="badge-label">{{ b.label }}</span>
108-
<span class="badge-fullname">{{ b.fullName }}</span>
109-
</div>
110-
<div class="badge-desc">{{ b.desc }}</div>
111-
</div>
112-
</TransitionGroup>
106+
{{ name }}
107+
</button>
108+
</div>
113109
</div>
114110

115-
<Transition name="slide-up">
116-
<button
117-
v-if="selected"
118-
class="ls-download"
119-
:disabled="downloading"
120-
@click="downloadLicense"
121-
>
122-
📄 {{ downloading ? 'Downloading...' : `Download ${selected} License` }}
123-
</button>
124-
</Transition>
111+
<!-- Badges + download -->
112+
<div class="ls-result">
113+
<div class="ls-badges-wrap">
114+
<TransitionGroup name="badge" tag="div" class="ls-badges">
115+
<div
116+
v-for="b in visibleBadges"
117+
:key="b.key"
118+
class="ls-badge"
119+
:style="{ '--badge-color': b.color }"
120+
>
121+
<span class="badge-icon">{{ b.icon }}</span>
122+
<div class="badge-text">
123+
<span class="badge-label">{{ b.label }}</span>
124+
<span class="badge-fullname">{{ b.fullName }}</span>
125+
</div>
126+
<div class="badge-desc">{{ b.desc }}</div>
127+
</div>
128+
</TransitionGroup>
129+
</div>
130+
131+
<Transition name="slide-up">
132+
<button
133+
v-if="selected"
134+
class="ls-download"
135+
:disabled="downloading"
136+
@click="downloadLicense"
137+
>
138+
📄 {{ downloading ? 'Downloading...' : `Download ${selected} License` }}
139+
</button>
140+
</Transition>
141+
</div>
125142
</div>
126143
</template>
127144

128145
<style scoped>
146+
/* Animated gradient angle */
147+
@property --border-angle {
148+
syntax: '<angle>';
149+
initial-value: 0deg;
150+
inherits: false;
151+
}
152+
129153
.ls-root {
130154
display: flex;
131155
flex-direction: column;
132156
align-items: center;
133157
gap: 12px;
134-
padding: 8px 0;
158+
padding: 4px 0;
159+
margin-top: -20px;
160+
width: 100%;
135161
}
136162
163+
/* Fixed-height slot so buttons don't shift when hint disappears */
164+
.ls-hint-slot {
165+
height: 24px;
166+
display: flex;
167+
align-items: center;
168+
justify-content: center;
169+
}
170+
171+
/* Hint */
137172
.ls-hint {
138173
font-size: 14px;
139-
color: var(--vp-c-text-2);
174+
font-weight: 700;
175+
color: var(--vp-c-brand-1);
140176
margin: 0;
141-
font-weight: 500;
177+
display: flex;
178+
align-items: center;
179+
gap: 6px;
180+
white-space: nowrap;
181+
}
182+
183+
.hint-arrow {
184+
display: inline-block;
185+
animation: nudge-down 1.5s ease-in-out infinite;
186+
}
187+
188+
@keyframes nudge-down {
189+
0%, 100% { transform: translateY(0); }
190+
50% { transform: translateY(3px); }
191+
}
192+
193+
.hint-enter-active { transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
194+
.hint-leave-active { transition: all 0.2s ease; }
195+
.hint-enter-from { opacity: 0; transform: translateY(-6px); }
196+
.hint-leave-to { opacity: 0; transform: translateY(-6px); }
197+
198+
/* Buttons area — relative container for the border overlay */
199+
.ls-buttons-area {
200+
position: relative;
201+
padding: 14px 18px;
142202
}
143203
204+
/* Rotating border ring — sits behind buttons as overlay */
205+
.ls-border-ring {
206+
position: absolute;
207+
inset: 0;
208+
border-radius: 18px;
209+
padding: 2px;
210+
background: conic-gradient(
211+
from var(--border-angle),
212+
var(--vp-c-brand-1),
213+
#2563eb,
214+
#16a34a,
215+
#ca8a04,
216+
#ea580c,
217+
var(--vp-c-brand-1)
218+
);
219+
animation: border-spin 3s linear infinite reverse;
220+
-webkit-mask:
221+
linear-gradient(#fff 0 0) content-box,
222+
linear-gradient(#fff 0 0);
223+
-webkit-mask-composite: xor;
224+
mask-composite: exclude;
225+
pointer-events: none;
226+
}
227+
228+
@keyframes border-spin {
229+
to { --border-angle: 360deg; }
230+
}
231+
232+
/* Box fade transition */
233+
.box-fade-enter-active { transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
234+
.box-fade-leave-active { transition: all 0.3s ease; }
235+
.box-fade-enter-from { opacity: 0; }
236+
.box-fade-leave-to { opacity: 0; }
237+
144238
/* License buttons */
145239
.ls-buttons {
146240
display: flex;
147241
flex-wrap: wrap;
148242
gap: 8px;
149243
justify-content: center;
244+
align-items: center;
150245
}
151246
152247
.ls-btn {
@@ -178,26 +273,36 @@ async function downloadLicense() {
178273
box-shadow: 0 3px 14px rgba(124, 58, 237, 0.25);
179274
}
180275
181-
/* Badges container — fixed height prevents hero shake */
276+
/* Result */
277+
.ls-result {
278+
display: flex;
279+
flex-direction: column;
280+
align-items: center;
281+
gap: 12px;
282+
width: 100%;
283+
}
284+
182285
.ls-badges-wrap {
183-
min-height: 100px;
286+
height: 46px;
184287
width: 100%;
288+
overflow: visible;
185289
}
186290
187291
.ls-badges {
188292
display: flex;
189293
flex-wrap: wrap;
190294
gap: 8px;
191295
justify-content: flex-start;
296+
align-items: center;
192297
}
193298
194-
/* Individual badge */
299+
/* Badge */
195300
.ls-badge {
196301
position: relative;
197302
display: flex;
198303
align-items: center;
199304
gap: 6px;
200-
padding: 8px 14px;
305+
padding: 6px 12px;
201306
background: var(--vp-c-bg-soft);
202307
border: 1.5px solid var(--vp-c-divider);
203308
border-radius: 10px;
@@ -211,7 +316,7 @@ async function downloadLicense() {
211316
}
212317
213318
.badge-icon {
214-
font-size: 18px;
319+
font-size: 16px;
215320
flex-shrink: 0;
216321
}
217322
@@ -222,18 +327,18 @@ async function downloadLicense() {
222327
}
223328
224329
.badge-label {
225-
font-size: 13px;
330+
font-size: 12px;
226331
font-weight: 800;
227332
color: var(--vp-c-text-1);
228333
}
229334
230335
.badge-fullname {
231-
font-size: 11px;
336+
font-size: 10px;
232337
color: var(--badge-color);
233338
font-weight: 500;
234339
}
235340
236-
/* Tooltip — absolute, doesn't affect layout */
341+
/* Tooltip */
237342
.badge-desc {
238343
position: absolute;
239344
top: calc(100% + 6px);
@@ -260,14 +365,11 @@ async function downloadLicense() {
260365
pointer-events: auto;
261366
}
262367
263-
/* === TransitionGroup animations === */
264-
265-
/* MOVE: remaining badges slide to new positions with spring physics */
368+
/* TransitionGroup */
266369
.badge-move {
267370
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
268371
}
269372
270-
/* ENTER: badges spring up from below */
271373
.badge-enter-active {
272374
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1),
273375
opacity 0.35s ease;
@@ -278,11 +380,9 @@ async function downloadLicense() {
278380
transform: translateY(40px) scale(0.6);
279381
}
280382
281-
/* LEAVE: badges fall with gravity + rotation */
282383
.badge-leave-active {
283384
transition: transform 0.45s cubic-bezier(0.55, 0, 1, 0.45),
284385
opacity 0.35s ease;
285-
/* Take out of flow so remaining items can move */
286386
position: absolute;
287387
}
288388
@@ -291,7 +391,7 @@ async function downloadLicense() {
291391
transform: translateY(80px) rotate(15deg) scale(0.5);
292392
}
293393
294-
/* Download button */
394+
/* Download */
295395
.ls-download {
296396
display: inline-flex;
297397
align-items: center;
@@ -318,19 +418,8 @@ async function downloadLicense() {
318418
cursor: wait;
319419
}
320420
321-
/* Slide-up transition for download button */
322-
.slide-up-enter-active {
323-
transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
324-
}
325-
.slide-up-leave-active {
326-
transition: all 0.25s ease;
327-
}
328-
.slide-up-enter-from {
329-
opacity: 0;
330-
transform: translateY(12px) scale(0.9);
331-
}
332-
.slide-up-leave-to {
333-
opacity: 0;
334-
transform: translateY(8px) scale(0.95);
335-
}
421+
.slide-up-enter-active { transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); }
422+
.slide-up-leave-active { transition: all 0.25s ease; }
423+
.slide-up-enter-from { opacity: 0; transform: translateY(12px) scale(0.9); }
424+
.slide-up-leave-to { opacity: 0; transform: translateY(8px) scale(0.95); }
336425
</style>

0 commit comments

Comments
 (0)