Compare commits

..

No commits in common. "7c44e555971cc7180ac00148ba2afe4ea731365d" and "bca16253afbcf3cd507d27f974a8c31ed3b53148" have entirely different histories.

13 changed files with 132 additions and 237 deletions

View File

@ -1,15 +1,14 @@
use async_stream::stream; use async_stream::stream;
use futures_util::{FutureExt, select, Stream, stream::StreamExt, TryStreamExt}; use futures_util::{select, stream::StreamExt, FutureExt, Stream, TryStreamExt};
use headers::UserAgent; use headers::UserAgent;
use hyper::body::Bytes; use hyper::body::Bytes;
use reqwest::{Client, redirect::Policy, RequestBuilder}; use magnetar_core::web_model::ContentType;
use reqwest::{redirect::Policy, Client, RequestBuilder};
use serde_json::Value; use serde_json::Value;
use thiserror::Error; use thiserror::Error;
use tokio::pin; use tokio::pin;
use url::Url; use url::Url;
use magnetar_core::web_model::ContentType;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FederationClient { pub struct FederationClient {
pub client: Client, pub client: Client,
@ -119,10 +118,8 @@ impl FederationRequestBuilder<'_> {
async fn send_stream( async fn send_stream(
self, self,
) -> Result<impl Stream<Item=Result<Bytes, FederationClientError>>, FederationClientError> ) -> Result<impl Stream<Item = Result<Bytes, FederationClientError>>, FederationClientError>
{ {
eprintln!("{:?}", self.builder);
let mut body = self let mut body = self
.builder .builder
.send() .send()
@ -149,7 +146,7 @@ impl FederationRequestBuilder<'_> {
let sleep = tokio::time::sleep(tokio::time::Duration::from_secs( let sleep = tokio::time::sleep(tokio::time::Duration::from_secs(
self.client.timeout_seconds, self.client.timeout_seconds,
)) ))
.fuse(); .fuse();
tokio::pin!(sleep); tokio::pin!(sleep);
let body = async move { let body = async move {
@ -161,7 +158,7 @@ impl FederationRequestBuilder<'_> {
}) })
.await .await
} }
.fuse(); .fuse();
pin!(body); pin!(body);

View File

@ -7,9 +7,8 @@
:pinned="pinned" :pinned="pinned"
> >
</XNote> </XNote>
<div class="spinner-container" v-else> <div v-else>
<MagSpinner /> <i class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"></i>
Fetching
</div> </div>
</template> </template>
@ -40,17 +39,6 @@ watch(
noteData.value = n; noteData.value = n;
}); });
}, },
{ immediate: true } { immediate: true },
); );
</script> </script>
<style scoped lang="scss">
.spinner-container {
margin: 12px 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2em;
gap: 0.4em;
}
</style>

View File

@ -69,13 +69,11 @@
<MagAvatar <MagAvatar
v-if="notif.type === 'Renote'" v-if="notif.type === 'Renote'"
class="icon" class="icon"
:class="{ 'is-read': notif.is_read }"
:user="notif.note.user" :user="notif.note.user"
/> />
<MagAvatar <MagAvatar
v-else-if="notif.type === 'Reaction'" v-else-if="notif.type === 'Reaction'"
class="icon" class="icon"
:class="{ 'is-read': notif.is_read }"
:user="notif.user" :user="notif.user"
/> />
<div class="sub-icon" :class="notif.type"> <div class="sub-icon" :class="notif.type">
@ -266,11 +264,6 @@ const hookTooltip = (
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 6px; border-radius: 6px;
&:not(.is-read) {
outline: 1px solid var(--accentDarken);
outline-offset: 2px;
}
} }
> .sub-icon { > .sub-icon {
@ -321,7 +314,7 @@ const hookTooltip = (
flex-wrap: wrap; flex-wrap: wrap;
align-items: baseline; align-items: baseline;
margin-inline-end: 10px; margin-inline-end: 10px;
gap: 0.4em; gap: 0.2em;
> .name { > .name {
text-overflow: ellipsis; text-overflow: ellipsis;
@ -329,15 +322,10 @@ const hookTooltip = (
overflow: hidden; overflow: hidden;
min-width: 0; min-width: 0;
flex: 0 1 auto; flex: 0 1 auto;
max-width: 150px; }
border: 1px solid var(--accentedBg);
border-radius: 20px;
padding-inline: 10px;
&:hover { > .name:not(:last-child)::after {
background-color: var(--accentedBg); content: ",";
border-color: var(--accent);
}
} }
} }

View File

@ -47,7 +47,10 @@
<a v-if="!pollRefreshing" @click.stop="refresh">{{ <a v-if="!pollRefreshing" @click.stop="refresh">{{
i18n.ts.reload i18n.ts.reload
}}</a> }}</a>
<MagSpinner v-else /> <i
v-else
class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"
></i>
</span> </span>
<span v-if="isVoted"> · {{ i18n.ts._poll.voted }}</span> <span v-if="isVoted"> · {{ i18n.ts._poll.voted }}</span>
<span v-else-if="closed"> · {{ i18n.ts._poll.closed }}</span> <span v-else-if="closed"> · {{ i18n.ts._poll.closed }}</span>
@ -74,31 +77,31 @@ const pollRefreshing = ref(false);
const remaining = ref(-1); const remaining = ref(-1);
const total = computed(() => const total = computed(() =>
sum(props.note.poll.options.map((x) => x.votes_count)) sum(props.note.poll.options.map((x) => x.votes_count)),
); );
const closed = computed(() => remaining.value === 0); const closed = computed(() => remaining.value === 0);
const isLocal = computed(() => !props.note.uri); const isLocal = computed(() => !props.note.uri);
const isVoted = computed( const isVoted = computed(
() => () =>
!props.note.poll.multiple_choice && !props.note.poll.multiple_choice &&
props.note.poll.options.some((c) => c.voted ?? false) props.note.poll.options.some((c) => c.voted ?? false),
); );
const timer = computed(() => const timer = computed(() =>
i18n.t( i18n.t(
remaining.value >= 86400 remaining.value >= 86400
? "_poll.remainingDays" ? "_poll.remainingDays"
: remaining.value >= 3600 : remaining.value >= 3600
? "_poll.remainingHours" ? "_poll.remainingHours"
: remaining.value >= 60 : remaining.value >= 60
? "_poll.remainingMinutes" ? "_poll.remainingMinutes"
: "_poll.remainingSeconds", : "_poll.remainingSeconds",
{ {
s: Math.floor(remaining.value % 60), s: Math.floor(remaining.value % 60),
m: Math.floor(remaining.value / 60) % 60, m: Math.floor(remaining.value / 60) % 60,
h: Math.floor(remaining.value / 3600) % 24, h: Math.floor(remaining.value / 3600) % 24,
d: Math.floor(remaining.value / 86400), d: Math.floor(remaining.value / 86400),
} },
) ),
); );
const showResult = ref(props.readOnly || isVoted.value); const showResult = ref(props.readOnly || isVoted.value);
@ -109,8 +112,8 @@ if (props.note.poll.expires_at) {
remaining.value = Math.floor( remaining.value = Math.floor(
Math.max( Math.max(
new Date(props.note.poll.expires_at!).getTime() - Date.now(), new Date(props.note.poll.expires_at!).getTime() - Date.now(),
0 0,
) / 1000 ) / 1000,
); );
if (remaining.value === 0) { if (remaining.value === 0) {
showResult.value = true; showResult.value = true;
@ -134,7 +137,7 @@ async function refresh() {
os.magApi( os.magApi(
endpoints.GetNoteById, endpoints.GetNoteById,
{ attachments: true }, { attachments: true },
{ id: obj.object.id } { id: obj.object.id },
).then((n) => { ).then((n) => {
props.note.poll = { ...toRaw(props.note.poll), ...n.poll }; props.note.poll = { ...toRaw(props.note.poll), ...n.poll };
}); });

View File

@ -1,6 +1,6 @@
<template> <template>
<template v-if="waitIncoming"> <template v-if="waitIncoming">
<MagSpinner /> <i class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"></i>
</template> </template>
<template v-else> <template v-else>
<button <button

View File

@ -44,7 +44,7 @@
> >
<!-- つまりリモートフォローの場合 --> <!-- つまりリモートフォローの場合 -->
<span>{{ (state = i18n.ts.processing) }}</span <span>{{ (state = i18n.ts.processing) }}</span
><MagSpinner /> ><i class="ph-circle-notch ph-bold ph-lg fa-pulse"></i>
</template> </template>
<template v-else-if="isFollowing"> <template v-else-if="isFollowing">
<span>{{ (state = i18n.ts.unfollow) }}</span <span>{{ (state = i18n.ts.unfollow) }}</span
@ -71,7 +71,7 @@
</template> </template>
<template v-else> <template v-else>
<span>{{ (state = i18n.ts.processing) }}</span <span>{{ (state = i18n.ts.processing) }}</span
><MagSpinner /> ><i class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"></i>
</template> </template>
</button> </button>
</template> </template>

View File

@ -52,6 +52,7 @@ const props = withDefaults(
{} {}
); );
let hide = ref(true); let hide = ref(true);
</script> </script>
@ -100,7 +101,6 @@ let hide = ref(true);
& fieldset.audio-player-frame { & fieldset.audio-player-frame {
border-color: var(--accentedBg); border-color: var(--accentedBg);
border-radius: 10px; border-radius: 10px;
border-style: solid;
& legend { & legend {
padding-inline: 5px; padding-inline: 5px;

View File

@ -47,17 +47,15 @@
v-tooltip:dialog="i18n.ts.usernameInfo" v-tooltip:dialog="i18n.ts.usernameInfo"
class="_button _help" class="_button _help"
> >
<i class="ph-question ph-bold"></i> <i class="ph-question ph-bold"></i></div
</div> ></template>
</template>
<template #prefix>@</template> <template #prefix>@</template>
<template #suffix>@{{ host }}</template> <template #suffix>@{{ host }}</template>
<template #caption> <template #caption>
<span <span v-if="usernameState === 'wait'" style="color: #6e6a86"
v-if="usernameState === 'wait'" ><i
style="color: #6e6a86" class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"
> ></i>
<MagSpinner />
{{ i18n.ts.checking }}</span {{ i18n.ts.checking }}</span
> >
<span <span
@ -115,15 +113,16 @@
v-tooltip:dialog="i18n.ts._signup.emailAddressInfo" v-tooltip:dialog="i18n.ts._signup.emailAddressInfo"
class="_button _help" class="_button _help"
> >
<i class="ph-question ph-bold"></i> <i class="ph-question ph-bold"></i></div
</div> ></template>
</template>
<template #prefix <template #prefix
><i class="ph-envelope-simple-open ph-bold ph-lg"></i ><i class="ph-envelope-simple-open ph-bold ph-lg"></i
></template> ></template>
<template #caption> <template #caption>
<span v-if="emailState === 'wait'" style="color: #6e6a86"> <span v-if="emailState === 'wait'" style="color: #6e6a86"
<MagSpinner /> ><i
class="ph-circle-notch ph-bold ph-lg fa-pulse ph-fw ph-lg"
></i>
{{ i18n.ts.checking }}</span {{ i18n.ts.checking }}</span
> >
<span <span
@ -220,8 +219,8 @@
@update:modelValue="onChangePasswordRetype" @update:modelValue="onChangePasswordRetype"
> >
<template #label <template #label
>{{ i18n.ts.password }} ({{ i18n.ts.retype }}) >{{ i18n.ts.password }} ({{ i18n.ts.retype }})</template
</template> >
<template #prefix <template #prefix
><i class="ph-lock ph-bold ph-lg"></i ><i class="ph-lock ph-bold ph-lg"></i
></template> ></template>
@ -278,14 +277,16 @@
:disabled="shouldDisableSubmitting" :disabled="shouldDisableSubmitting"
gradate gradate
data-cy-signup-submit data-cy-signup-submit
>{{ i18n.ts.start }} >{{ i18n.ts.start }}</MkButton
</MkButton> >
</div> </div>
</form> </form>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref } from "vue"; import { ref, computed } from "vue";
import {} from "vue";
import getPasswordStrength from "syuilo-password-strength"; import getPasswordStrength from "syuilo-password-strength";
import { toUnicode } from "punycode/"; import { toUnicode } from "punycode/";
import MkButton from "./MkButton.vue"; import MkButton from "./MkButton.vue";
@ -304,7 +305,7 @@ const props = withDefaults(
}>(), }>(),
{ {
autoSet: false, autoSet: false,
} },
); );
const emit = defineEmits<{ const emit = defineEmits<{
@ -378,10 +379,10 @@ function onChangeUsername(): void {
const err = !username.value.match(/^[a-zA-Z0-9_]+$/) const err = !username.value.match(/^[a-zA-Z0-9_]+$/)
? "invalid-format" ? "invalid-format"
: username.value.length < 1 : username.value.length < 1
? "min-range" ? "min-range"
: username.value.length > 20 : username.value.length > 20
? "max-range" ? "max-range"
: null; : null;
if (err) { if (err) {
usernameState.value = err; usernameState.value = err;
@ -417,16 +418,16 @@ function onChangeEmail(): void {
emailState.value = result.available emailState.value = result.available
? "ok" ? "ok"
: result.reason === "used" : result.reason === "used"
? "unavailable:used" ? "unavailable:used"
: result.reason === "format" : result.reason === "format"
? "unavailable:format" ? "unavailable:format"
: result.reason === "disposable" : result.reason === "disposable"
? "unavailable:disposable" ? "unavailable:disposable"
: result.reason === "mx" : result.reason === "mx"
? "unavailable:mx" ? "unavailable:mx"
: result.reason === "smtp" : result.reason === "smtp"
? "unavailable:smtp" ? "unavailable:smtp"
: "unavailable"; : "unavailable";
}) })
.catch(() => { .catch(() => {
emailState.value = "error"; emailState.value = "error";

View File

@ -1,80 +0,0 @@
<template>
<i class="simple ph-hourglass ph-bold ph-lg" :aria-label="i18n.ts.busy"></i>
<svg
class="animated mag-spinner"
width="32"
height="32"
version="1.1"
viewBox="0 0 67.733 67.733"
xmlns="http://www.w3.org/2000/svg"
>
<g class="mag-ring" transform="matrix(.82287 0 0 .82287 5.9984 5.9989)">
<path
d="m33.959 0.8413c-8.3737-0.008823-16.592 3.1643-22.849 9.1188-8.8995 8.4685-12.376 21.177-9.023 32.996l5.9686-1.681c-2.7249-9.6065 0.095231-19.927 7.329-26.811 7.2337-6.8834 17.845-8.9517 26.103-6.264l1.9737-5.9045c-2.9094-0.98361-4.8438-1.2553-7.8257-1.41-0.55911-0.028992-1.1178-0.044097-1.676-0.04468zm31.826 24.715-6.0201 1.553c2.4674 9.2417-0.15852 19.094-6.8993 25.88-6.7409 6.7861-16.177 9.1968-25.564 6.8428l-1.6444 5.9555c11.39 2.9597 23.3-0.07129 31.594-8.4205 8.2936-8.3492 11.569-20.441 8.5336-31.811z"
fill="currentColor"
/>
</g>
<g
class="mag-butterflies"
transform="matrix(1.2958 .098299 -.098299 1.2958 .41715 -18.811)"
>
<path
d="m19.244 39.965c-0.62132 0.75445-1.2862 1.4845-1.8805 2.2541-0.45826 1.4275-0.95911 2.8484-1.3908 4.28 0.01197 0.7973 0.02382 1.5946 0.03574 2.3919-0.82611-0.0559-1.656-0.15529-2.4798-0.18435-1.4482 0.38557-2.9176 0.72632-4.3525 1.1398-0.76206 0.56257-1.5241 1.1251-2.2862 1.6877 0.00746 0.57752 0.014929 1.155 0.022392 1.7326 0.85814 0.49688 1.6647 1.0953 2.6101 1.4204 0.76646 0.32006 1.5329 0.64012 2.2994 0.96018 0.53911-0.39567 1.0782-0.79134 1.6173-1.187 0.01331 0.4126 0.02652 0.82522 0.03983 1.2378 0.55847 0.37816 1.0935 0.81873 1.6666 1.1579 0.94848 0.09538 1.897 0.19074 2.8454 0.28611 0.79636-0.46986 1.5927-0.93971 2.3891-1.4096-0.14459-0.67269-0.24382-1.3636-0.41647-2.025-0.40398-0.62711-0.79926-1.2606-1.2086-1.8838 0.62691 0.4569 1.2427 0.94576 1.8866 1.3706 0.63581 0.16906 1.2716 0.33814 1.9074 0.5072 0.52106-0.76381 1.0421-1.5276 1.5632-2.2914-0.05014-0.9802-0.03649-1.9797-0.12641-2.9479-0.33964-0.54964-0.67928-1.0993-1.0189-1.6489-0.41083-0.04035-0.82165-0.08069-1.2325-0.12099 0.43013-0.51202 0.86026-1.024 1.2904-1.5361-0.39788-1.1174-0.74239-2.2576-1.1736-3.3607-0.29327-0.56483-0.58654-1.1297-0.8798-1.6945-0.5758-0.0454-1.1516-0.09072-1.7274-0.13608z"
fill="currentColor"
/>
</g>
<g
class="mag-butterflies"
transform="matrix(-1.2957 -.098293 .098293 -1.2957 66.781 86.854)"
>
<path
d="m19.244 39.965c-0.62132 0.75445-1.2862 1.4845-1.8805 2.2541-0.45826 1.4275-0.95911 2.8484-1.3908 4.28 0.01197 0.7973 0.02382 1.5946 0.03574 2.3919-0.82611-0.0559-1.656-0.15529-2.4798-0.18435-1.4482 0.38557-2.9176 0.72632-4.3525 1.1398-0.76206 0.56257-1.5241 1.1251-2.2862 1.6877 0.00746 0.57752 0.014929 1.155 0.022392 1.7326 0.85814 0.49688 1.6647 1.0953 2.6101 1.4204 0.76646 0.32006 1.5329 0.64012 2.2994 0.96018 0.53911-0.39567 1.0782-0.79134 1.6173-1.187 0.01331 0.4126 0.02652 0.82522 0.03983 1.2378 0.55847 0.37816 1.0935 0.81873 1.6666 1.1579 0.94848 0.09538 1.897 0.19074 2.8454 0.28611 0.79636-0.46986 1.5927-0.93971 2.3891-1.4096-0.14459-0.67269-0.24382-1.3636-0.41647-2.025-0.40398-0.62711-0.79926-1.2606-1.2086-1.8838 0.62691 0.4569 1.2427 0.94576 1.8866 1.3706 0.63581 0.16906 1.2716 0.33814 1.9074 0.5072 0.52106-0.76381 1.0421-1.5276 1.5632-2.2914-0.05014-0.9802-0.03649-1.9797-0.12641-2.9479-0.33964-0.54964-0.67928-1.0993-1.0189-1.6489-0.41083-0.04035-0.82165-0.08069-1.2325-0.12099 0.43013-0.51202 0.86026-1.024 1.2904-1.5361-0.39788-1.1174-0.74239-2.2576-1.1736-3.3607-0.29327-0.56483-0.58654-1.1297-0.8798-1.6945-0.5758-0.0454-1.1516-0.09072-1.7274-0.13608z"
fill="currentColor"
/>
</g>
</svg>
</template>
<script setup lang="ts">
import { i18n } from "@/i18n";
</script>
<style scoped lang="scss">
.simple {
display: none;
}
.mag-spinner.animated {
display: inline-block;
height: 100%;
aspect-ratio: 1 / 1;
width: auto;
transform-origin: center;
animation-name: mag-ring-rotate;
animation-timing-function: linear;
animation-direction: normal;
animation-duration: 3s;
animation-iteration-count: infinite;
}
@keyframes mag-ring-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion) {
.simple {
display: initial;
}
.animated {
display: none;
}
}
</style>

View File

@ -1,50 +1,37 @@
<template> <template>
<svg <div
aria-hidden="true"
:class="[ :class="[
$style['mag-spinner-loading'], $style.root,
{ {
[$style.inline]: inline, [$style.inline]: inline,
[$style.colored]: colored, [$style.colored]: colored,
[$style.mini]: mini, [$style.mini]: mini,
}, },
]" ]"
width="32"
height="32"
version="1.1"
viewBox="0 0 67.733 67.733"
xmlns="http://www.w3.org/2000/svg"
> >
<g :class="$style['mag-spinner-spin']"> <div :class="$style.container" aria-hidden="true">
<g transform="matrix(.82287 0 0 .82287 5.9984 5.9989)"> <svg
<path :class="[$style.spinner]"
d="m33.959 0.8413c-8.3737-0.008823-16.592 3.1643-22.849 9.1188-8.8995 8.4685-12.376 21.177-9.023 32.996l5.9686-1.681c-2.7249-9.6065 0.095231-19.927 7.329-26.811 7.2337-6.8834 17.845-8.9517 26.103-6.264l1.9737-5.9045c-2.9094-0.98361-4.8438-1.2553-7.8257-1.41-0.55911-0.028992-1.1178-0.044097-1.676-0.04468zm31.826 24.715-6.0201 1.553c2.4674 9.2417-0.15852 19.094-6.8993 25.88-6.7409 6.7861-16.177 9.1968-25.564 6.8428l-1.6444 5.9555c11.39 2.9597 23.3-0.07129 31.594-8.4205 8.2936-8.3492 11.569-20.441 8.5336-31.811z" viewBox="0 0 50 50"
fill="currentColor" xmlns="http://www.w3.org/2000/svg"
/>
</g>
<g
:class="$style['mag-butterflies']"
transform="matrix(1.2958 .098299 -.098299 1.2958 .41715 -18.811)"
> >
<path <circle
d="m19.244 39.965c-0.62132 0.75445-1.2862 1.4845-1.8805 2.2541-0.45826 1.4275-0.95911 2.8484-1.3908 4.28 0.01197 0.7973 0.02382 1.5946 0.03574 2.3919-0.82611-0.0559-1.656-0.15529-2.4798-0.18435-1.4482 0.38557-2.9176 0.72632-4.3525 1.1398-0.76206 0.56257-1.5241 1.1251-2.2862 1.6877 0.00746 0.57752 0.014929 1.155 0.022392 1.7326 0.85814 0.49688 1.6647 1.0953 2.6101 1.4204 0.76646 0.32006 1.5329 0.64012 2.2994 0.96018 0.53911-0.39567 1.0782-0.79134 1.6173-1.187 0.01331 0.4126 0.02652 0.82522 0.03983 1.2378 0.55847 0.37816 1.0935 0.81873 1.6666 1.1579 0.94848 0.09538 1.897 0.19074 2.8454 0.28611 0.79636-0.46986 1.5927-0.93971 2.3891-1.4096-0.14459-0.67269-0.24382-1.3636-0.41647-2.025-0.40398-0.62711-0.79926-1.2606-1.2086-1.8838 0.62691 0.4569 1.2427 0.94576 1.8866 1.3706 0.63581 0.16906 1.2716 0.33814 1.9074 0.5072 0.52106-0.76381 1.0421-1.5276 1.5632-2.2914-0.05014-0.9802-0.03649-1.9797-0.12641-2.9479-0.33964-0.54964-0.67928-1.0993-1.0189-1.6489-0.41083-0.04035-0.82165-0.08069-1.2325-0.12099 0.43013-0.51202 0.86026-1.024 1.2904-1.5361-0.39788-1.1174-0.74239-2.2576-1.1736-3.3607-0.29327-0.56483-0.58654-1.1297-0.8798-1.6945-0.5758-0.0454-1.1516-0.09072-1.7274-0.13608z" :class="[$style.path]"
fill="currentColor" cx="25"
/> cy="25"
</g> r="20"
<g fill="none"
:class="$style['mag-butterflies']" stroke-width="6px"
transform="matrix(-1.2957 -.098293 .098293 -1.2957 66.781 86.854)" style="fill: none; stroke: currentColor; stroke-width: 6px"
> ></circle>
<path </svg>
d="m19.244 39.965c-0.62132 0.75445-1.2862 1.4845-1.8805 2.2541-0.45826 1.4275-0.95911 2.8484-1.3908 4.28 0.01197 0.7973 0.02382 1.5946 0.03574 2.3919-0.82611-0.0559-1.656-0.15529-2.4798-0.18435-1.4482 0.38557-2.9176 0.72632-4.3525 1.1398-0.76206 0.56257-1.5241 1.1251-2.2862 1.6877 0.00746 0.57752 0.014929 1.155 0.022392 1.7326 0.85814 0.49688 1.6647 1.0953 2.6101 1.4204 0.76646 0.32006 1.5329 0.64012 2.2994 0.96018 0.53911-0.39567 1.0782-0.79134 1.6173-1.187 0.01331 0.4126 0.02652 0.82522 0.03983 1.2378 0.55847 0.37816 1.0935 0.81873 1.6666 1.1579 0.94848 0.09538 1.897 0.19074 2.8454 0.28611 0.79636-0.46986 1.5927-0.93971 2.3891-1.4096-0.14459-0.67269-0.24382-1.3636-0.41647-2.025-0.40398-0.62711-0.79926-1.2606-1.2086-1.8838 0.62691 0.4569 1.2427 0.94576 1.8866 1.3706 0.63581 0.16906 1.2716 0.33814 1.9074 0.5072 0.52106-0.76381 1.0421-1.5276 1.5632-2.2914-0.05014-0.9802-0.03649-1.9797-0.12641-2.9479-0.33964-0.54964-0.67928-1.0993-1.0189-1.6489-0.41083-0.04035-0.82165-0.08069-1.2325-0.12099 0.43013-0.51202 0.86026-1.024 1.2904-1.5361-0.39788-1.1174-0.74239-2.2576-1.1736-3.3607-0.29327-0.56483-0.58654-1.1297-0.8798-1.6945-0.5758-0.0454-1.1516-0.09072-1.7274-0.13608z" </div>
fill="currentColor" </div>
/>
</g>
</g>
</svg>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {} from "vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
inline?: boolean; inline?: boolean;
@ -57,12 +44,14 @@ const props = withDefaults(
colored: true, colored: true,
mini: false, mini: false,
em: false, em: false,
} },
); );
</script> </script>
<style lang="scss" module> <style lang="scss" module>
@keyframes mag-loading-spin { /* Credit to https://codepen.io/supah/pen/BjYLdW */
@keyframes spin {
0% { 0% {
transform: rotate(0deg); transform: rotate(0deg);
} }
@ -71,33 +60,25 @@ const props = withDefaults(
} }
} }
@keyframes mag-loading-butterfly-appear { @keyframes dash {
0% { 0% {
opacity: 0; stroke-dasharray: 1, 150;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -35;
} }
100% { 100% {
opacity: 1; stroke-dasharray: 90, 150;
stroke-dashoffset: -124;
} }
} }
.mag-butterflies { .root {
opacity: 0; padding: 32px;
animation: 1s mag-loading-butterfly-appear 0s 1 ease-out forwards; text-align: center;
}
.mag-spinner-spin {
animation: 2.5s mag-loading-spin infinite linear;
transform-origin: center;
}
.mag-spinner-loading {
display: block;
position: relative;
margin-block: 32px;
cursor: wait; cursor: wait;
width: var(--size);
height: var(--size);
--size: 40px; --size: 40px;
@ -107,22 +88,42 @@ const props = withDefaults(
&.inline { &.inline {
display: inline; display: inline;
padding: 0;
--size: 32px; --size: 32px;
} }
&.mini { &.mini {
margin: 16px; padding: 16px;
--size: 16px; --size: 32px;
} }
&:not(.inline) {
margin-inline: auto;
}
&.em { &.em {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0;
--size: 1em; --size: 1em;
} }
} }
.container {
position: relative;
width: var(--size);
height: var(--size);
margin: 0 auto;
}
.spinner {
position: absolute;
top: 0;
left: 0;
z-index: 999;
width: var(--size);
height: var(--size);
animation: spin 2s linear infinite;
}
.path {
stroke: var(--accent);
stroke-linecap: round;
animation: dash 1.2s ease-in-out infinite;
}
</style> </style>

View File

@ -60,14 +60,12 @@ import MkError from "./components/global/MkError.vue";
import MkPageHeader from "./components/global/MkPageHeader.vue"; import MkPageHeader from "./components/global/MkPageHeader.vue";
import MkSpacer from "./components/global/MkSpacer.vue"; import MkSpacer from "./components/global/MkSpacer.vue";
import MkStickyContainer from "./components/global/MkStickyContainer.vue"; import MkStickyContainer from "./components/global/MkStickyContainer.vue";
import MagSpinner from "@/components/global/MagSpinner.vue";
function globalComponents(app: App) { function globalComponents(app: App) {
app.component("I18n", I18n); app.component("I18n", I18n);
app.component("RouterView", RouterView); app.component("RouterView", RouterView);
app.component("Mfm", Mfm); app.component("Mfm", Mfm);
app.component("MkA", MkA); app.component("MkA", MkA);
app.component("MagSpinner", MagSpinner);
app.component("MkAcct", MkAcct); app.component("MkAcct", MkAcct);
app.component("MagAvatar", MagAvatar); app.component("MagAvatar", MagAvatar);
app.component("MagEmoji", MagEmoji); app.component("MagEmoji", MagEmoji);
@ -89,7 +87,6 @@ declare module "@vue/runtime-core" {
RouterView: typeof RouterView; RouterView: typeof RouterView;
Mfm: typeof Mfm; Mfm: typeof Mfm;
MkA: typeof MkA; MkA: typeof MkA;
MagSpinner: typeof MagSpinner;
MkAcct: typeof MkAcct; MkAcct: typeof MkAcct;
MagAvatar: typeof MagAvatar; MagAvatar: typeof MagAvatar;
MagEmoji: typeof MagEmoji; MagEmoji: typeof MagEmoji;

View File

@ -8,7 +8,8 @@
></div> ></div>
<div class="top"> <div class="top">
<p class="name"> <p class="name">
<MagSpinner />{{ ctx.name }} <i class="ph-circle-notch ph-bold ph-lg fa-pulse"></i
>{{ ctx.name }}
</p> </p>
<p class="status"> <p class="status">
<span <span

View File

@ -34,7 +34,6 @@ loggingIn: "Signing In"
logout: "Sign Out" logout: "Sign Out"
signup: "Sign Up" signup: "Sign Up"
uploading: "Uploading..." uploading: "Uploading..."
busy: "Busy..."
save: "Save" save: "Save"
users: "Users" users: "Users"
addUser: "Add a user" addUser: "Add a user"