- 顶上「快拿到了」三个只说还差什么,旁边「本班」:最近谁拿到了什么、成就最多前五(自己不在就钉在底下) - 38 个成就按指标收成一条条线、分五组,同一串几档排在一根进度线上,下一档标「差几」; 悬停看说明、哪天拿到、本班几人有、全站几人有 - 还没找到的隐藏成就只露问号;本班动态里也只说「彩蛋」,不漏名字 - 题单奖章并进「题单和比赛」那组;看别人的成就只有成就线 - 去掉「仅 X% 的人获得」(分母是全站历届账号)和完成度圆环 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
85108df9d8
commit
cbeb0737ef
9 files changed
+1203
-145
No files matched your search
@@ -0,0 +1,117 @@
|
||||
<script setup lang="ts">
|
||||
import { useThemeVars } from "naive-ui"
|
||||
import AchievementIcon from "shared/components/AchievementIcon.vue"
|
||||
import { RARITY_COLOR } from "utils/constants"
|
||||
import type { AchievementRarity } from "utils/types"
|
||||
|
||||
/**
|
||||
* 一枚徽章:拿到的是稀有度色的圈,没拿到的灰掉,还没找到的隐藏成就是虚线问号。
|
||||
* `ring` 给了就在外面画一圈进度(「快拿到了」那几个)。
|
||||
*/
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
icon?: string
|
||||
rarity?: AchievementRarity
|
||||
size?: number
|
||||
state?: "on" | "off" | "unknown"
|
||||
ring?: number | null
|
||||
}>(),
|
||||
{ icon: "", rarity: "bronze", size: 40, state: "on", ring: null },
|
||||
)
|
||||
|
||||
const theme = useThemeVars()
|
||||
const color = computed(() => RARITY_COLOR[props.rarity])
|
||||
const r = computed(() => props.size / 2 + 3)
|
||||
const box = computed(() => props.size + 8)
|
||||
const circumference = computed(() => 2 * Math.PI * r.value)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="medal" :style="{ width: `${size}px`, height: `${size}px` }">
|
||||
<svg
|
||||
v-if="ring !== null && state !== 'unknown'"
|
||||
class="arc"
|
||||
:width="box"
|
||||
:height="box"
|
||||
:viewBox="`0 0 ${box} ${box}`"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle :cx="box / 2" :cy="box / 2" :r="r" fill="none" class="arc-track" stroke-width="3" />
|
||||
<circle
|
||||
:cx="box / 2"
|
||||
:cy="box / 2"
|
||||
:r="r"
|
||||
fill="none"
|
||||
class="arc-fill"
|
||||
stroke-width="3"
|
||||
stroke-linecap="round"
|
||||
:stroke-dasharray="`${circumference * Math.min(1, ring)} ${circumference}`"
|
||||
/>
|
||||
</svg>
|
||||
<span v-if="state === 'unknown'" class="disc unknown" :style="{ fontSize: `${size * 0.42}px` }">
|
||||
?
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="disc"
|
||||
:class="state"
|
||||
:style="state === 'on' ? { borderColor: color, background: `${color}26` } : undefined"
|
||||
>
|
||||
<AchievementIcon :icon="icon" :size="Math.round(size * 0.56)" />
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.medal {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.arc {
|
||||
position: absolute;
|
||||
left: -4px;
|
||||
top: -4px;
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.arc-track {
|
||||
stroke: v-bind("theme.dividerColor");
|
||||
}
|
||||
|
||||
.arc-fill {
|
||||
stroke: v-bind("theme.primaryColor");
|
||||
}
|
||||
|
||||
.disc {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border-radius: 50%;
|
||||
border: 2px solid transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.disc.off {
|
||||
border-color: v-bind("theme.borderColor");
|
||||
background: v-bind("theme.actionColor");
|
||||
}
|
||||
|
||||
.disc.off :deep(svg),
|
||||
.disc.off :deep(img),
|
||||
.disc.off :deep(span) {
|
||||
filter: grayscale(1);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.disc.unknown {
|
||||
border: 1.5px dashed v-bind("theme.borderColor");
|
||||
background: v-bind("theme.actionColor");
|
||||
color: v-bind("theme.textColor3");
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user