This commit is contained in:
limepotato 2024-07-05 17:20:29 -06:00 committed by Iceshrimp development
parent 52792b706e
commit 8b4a927bce
3 changed files with 213 additions and 209 deletions

BIN
.yarn/cache/libopenmpt-wasm-https-c2e0cb89a7-ace14fcb0e.zip (Stored with Git LFS) vendored Normal file

Binary file not shown.

View file

@ -1,224 +1,225 @@
<template> <template>
<div> <div>
<div v-if="achievements" class="root"> <div v-if="achievements" :class="'.root'">
<div v-for="achievement in achievements" :key="achievement" class="_panel achievement"> <div v-for="achievement in achievements" :key="achievement" :class="'.achievement'" class="_panel">
<div class="icon"> <div :class="'.icon'">
<div :class="[['iconFrame'], ['iconFrame_' + ACHIEVEMENT_BADGES[achievement.name].frame]]"> <div :class="['.iconFrame', ['iconFrame_' + ACHIEVEMENT_BADGES[achievement.name].frame]]">
<div class="iconInner" :style="{ background: ACHIEVEMENT_BADGES[achievement.name].bg }"> <div :class="['.iconInner']" :style="{ background: ACHIEVEMENT_BADGES[achievement.name].bg }">
<img class="iconImg" :src="ACHIEVEMENT_BADGES[achievement.name].img"> <img :class="'.iconImg'" :src="ACHIEVEMENT_BADGES[achievement.name].img">
</div>
</div> </div>
</div> </div>
</div> <div :class="'.body'">
<div class="body"> <div :class="'.header'">
<div class="header"> <span :class="'.title'">{{ i18n.ts._achievements._types['_' + achievement.name].title }}</span>
<span class="title">{{ i18n.ts._achievements._types['_' + achievement.name].title }}</span> <span :class="'.time'">
<span class="time"> <time v-tooltip="new Date(achievement.unlockedAt).toLocaleString()">{{ new Date(achievement.unlockedAt).getFullYear() }}/{{ new Date(achievement.unlockedAt).getMonth() + 1 }}/{{ new Date(achievement.unlockedAt).getDate() }}</time>
<time v-tooltip="new Date(achievement.unlockedAt).toLocaleString()">{{ new Date(achievement.unlockedAt).getFullYear() }}/{{ new Date(achievement.unlockedAt).getMonth() + 1 }}/{{ new Date(achievement.unlockedAt).getDate() }}</time> </span>
</span> </div>
<div :class="'.description'">{{ i18n.ts._achievements._types['_' + achievement.name].description }}</div>
<div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor" :class="'.flavor'">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div>
</div> </div>
<div class="description">{{ i18n.ts._achievements._types['_' + achievement.name].description }}</div>
<div v-if="i18n.ts._achievements._types['_' + achievement.name].flavor" class="flavor">{{ i18n.ts._achievements._types['_' + achievement.name].flavor }}</div>
</div> </div>
<template v-if="withLocked">
<div v-for="achievement in lockedAchievements" :key="achievement" :class="['.achievement', '.locked']" class="_panel" @click="achievement === 'clickedClickHere' ? clickHere() : () => {}">
<div :class="'.icon'">
</div>
<div :class="'.body'">
<div :class="'.header'">
<span :class="'.title'">???</span>
</div>
<div :class="'.description'">???</div>
</div>
</div>
</template>
</div>
<div v-else>
<MkLoading/>
</div> </div>
<template v-if="withLocked">
<div v-for="achievement in lockedAchievements" :key="achievement" class="_panel achievement locked" @click="achievement === 'clickedClickHere' ? clickHere() : () => {}">
<div class="icon">
</div>
<div class="body">
<div class="header">
<span class="title">???</span>
</div>
<div class="description">???</div>
</div>
</div>
</template>
</div> </div>
<div v-else> </template>
<MkLoading/>
</div> <script lang="ts" setup>
</div> import * as misskey from 'misskey-js';
</template> import { onMounted } from 'vue';
import * as os from '@/os';
<script lang="ts" setup> import { i18n } from '@/i18n';
import * as misskey from 'misskey-js'; import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/scripts/achievements';
import { onMounted } from 'vue';
import * as os from '@/os'; const props = withDefaults(defineProps<{
import { i18n } from '@/i18n'; user: misskey.entities.User;
import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/scripts/achievements'; withLocked: boolean;
}>(), {
const props = withDefaults(defineProps<{ withLocked: true,
user: misskey.entities.User;
withLocked: boolean;
}>(), {
withLocked: true,
});
let achievements = $ref();
const lockedAchievements = $computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements ?? []).some(a => a.name === x)));
function fetch() {
os.api('users/achievements', { userId: props.user.id }).then(res => {
achievements = [];
for (const t of ACHIEVEMENT_TYPES) {
const a = res.find(x => x.name === t);
if (a) achievements.push(a);
}
//achievements = res.sort((a, b) => b.unlockedAt - a.unlockedAt);
}); });
}
let achievements = $ref();
function clickHere() { const lockedAchievements = $computed(() => ACHIEVEMENT_TYPES.filter(x => !(achievements ?? []).some(a => a.name === x)));
claimAchievement('clickedClickHere');
fetch(); function fetch() {
} os.api('users/achievements', { userId: props.user.id }).then(res => {
achievements = [];
onMounted(() => { for (const t of ACHIEVEMENT_TYPES) {
fetch(); const a = res.find(x => x.name === t);
}); if (a) achievements.push(a);
</script> }
//achievements = res.sort((a, b) => b.unlockedAt - a.unlockedAt);
<style lang="scss" scoped> });
.root {
display: grid;
grid-template-columns: repeat(auto-fill, min(380px, 100%));
grid-gap: 12px;
place-content: center;
}
.achievement {
display: flex;
padding: 16px;
&.locked {
opacity: 0.5;
} }
}
function clickHere() {
.icon { claimAchievement('clickedClickHere');
flex-shrink: 0; fetch();
margin-right: 12px;
}
@keyframes shine {
0% { translate: -30px; }
100% { translate: -130px; }
}
.iconFrame {
width: 58px;
height: 58px;
padding: 6px;
border-radius: 100%;
box-sizing: border-box;
pointer-events: none;
user-select: none;
filter: drop-shadow(0px 2px 2px #00000044);
box-shadow: 0 1px 0px #ffffff88 inset;
overflow: clip;
}
.iconFrame_bronze {
background: linear-gradient(0deg, #703827, #d37566);
> .iconInner {
background: linear-gradient(0deg, #d37566, #703827);
} }
}
.iconFrame_silver { onMounted(() => {
background: linear-gradient(0deg, #7c7c7c, #e1e1e1); fetch();
});
> .iconInner { </script>
background: linear-gradient(0deg, #e1e1e1, #7c7c7c);
<style lang="scss" module>
.root {
display: grid;
grid-template-columns: repeat(auto-fill, min(380px, 100%));
grid-gap: 12px;
place-content: center;
} }
}
.iconFrame_gold { .achievement {
background: linear-gradient(0deg, rgba(255,182,85,1) 0%, rgba(233,133,0,1) 49%, rgba(255,243,93,1) 51%, rgba(255,187,25,1) 100%); display: flex;
padding: 16px;
> .iconInner {
background: linear-gradient(0deg, #ffee20, #eb7018); &.locked {
opacity: 0.5;
}
} }
&:before { .icon {
content: ""; flex-shrink: 0;
display: block; margin-right: 12px;
}
@keyframes shine {
0% { translate: -30px; }
100% { translate: -130px; }
}
.iconFrame {
width: 58px;
height: 58px;
padding: 6px;
border-radius: 100%;
box-sizing: border-box;
pointer-events: none;
user-select: none;
filter: drop-shadow(0px 2px 2px #00000044);
box-shadow: 0 1px 0px #ffffff88 inset;
overflow: clip;
}
.iconFrame_bronze {
background: linear-gradient(0deg, #703827, #d37566);
> .iconInner {
background: linear-gradient(0deg, #d37566, #703827);
}
}
.iconFrame_silver {
background: linear-gradient(0deg, #7c7c7c, #e1e1e1);
> .iconInner {
background: linear-gradient(0deg, #e1e1e1, #7c7c7c);
}
}
.iconFrame_gold {
background: linear-gradient(0deg, rgba(255,182,85,1) 0%, rgba(233,133,0,1) 49%, rgba(255,243,93,1) 51%, rgba(255,187,25,1) 100%);
> .iconInner {
background: linear-gradient(0deg, #ffee20, #eb7018);
}
&:before {
content: "";
display: block;
position: absolute;
top: 30px;
width: 200px;
height: 8px;
rotate: -45deg;
translate: -30px;
background: #ffffff88;
animation: shine 2s infinite;
}
}
.iconFrame_platinum {
background: linear-gradient(0deg, rgba(154,154,154,1) 0%, rgba(226,226,226,1) 49%, rgba(255,255,255,1) 51%, rgba(195,195,195,1) 100%);
> .iconInner {
background: linear-gradient(0deg, #e1e1e1, #7c7c7c);
}
&:before {
content: "";
display: block;
position: absolute;
top: 30px;
width: 200px;
height: 8px;
rotate: -45deg;
translate: -30px;
background: #ffffffee;
animation: shine 2s infinite;
}
}
.iconInner {
position: relative;
width: 100%;
height: 100%;
border-radius: 100%;
box-shadow: 0 1px 0px #ffffff88 inset;
}
.iconImg {
width: calc(100% - 12px);
height: calc(100% - 12px);
position: absolute; position: absolute;
top: 30px; top: 0;
width: 200px; right: 0;
height: 8px; bottom: 0;
rotate: -45deg; left: 0;
translate: -30px; margin: auto;
background: #ffffff88; filter: drop-shadow(0px 1px 2px #000000aa);
animation: shine 2s infinite;
} }
}
.iconFrame_platinum { .body {
background: linear-gradient(0deg, rgba(154,154,154,1) 0%, rgba(226,226,226,1) 49%, rgba(255,255,255,1) 51%, rgba(195,195,195,1) 100%); flex: 1;
min-width: 0;
> .iconInner {
background: linear-gradient(0deg, #e1e1e1, #7c7c7c);
} }
&:before { .header {
content: ""; margin-bottom: 8px;
display: block; display: flex;
position: absolute;
top: 30px;
width: 200px;
height: 8px;
rotate: -45deg;
translate: -30px;
background: #ffffffee;
animation: shine 2s infinite;
} }
}
.title {
.iconInner { font-weight: bold;
position: relative; }
width: 100%;
height: 100%; .time {
border-radius: 100%; margin-left: auto;
box-shadow: 0 1px 0px #ffffff88 inset; font-size: 85%;
} opacity: 0.7;
}
.iconImg {
width: calc(100% - 12px); .description {
height: calc(100% - 12px); font-size: 85%;
position: absolute; }
top: 0;
right: 0; .flavor {
bottom: 0; opacity: 0.7;
left: 0; transform: skewX(-15deg);
margin: auto; font-size: 85%;
filter: drop-shadow(0px 1px 2px #000000aa); margin-top: 8px;
} }
</style>
.body {
flex: 1;
min-width: 0;
}
.header {
margin-bottom: 8px;
display: flex;
}
.title {
font-weight: bold;
}
.time {
margin-left: auto;
font-size: 85%;
opacity: 0.7;
}
.description {
font-size: 85%;
}
.flavor {
opacity: 0.7;
transform: skewX(-15deg);
font-size: 85%;
margin-top: 8px;
}
</style>

View file

@ -225,7 +225,7 @@
<MkA <MkA
v-if="notification.type === 'achievementEarned'" v-if="notification.type === 'achievementEarned'"
class="text" class="text"
:to="/my/achievements"> :to="'/my/achievements'">
{{ i18n.ts._achievements._types['_' + notification.achievement].title }} {{ i18n.ts._achievements._types['_' + notification.achievement].title }}
</MkA> </MkA>
<span <span