summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/frontend/src/components/MkNote.vue558
-rw-r--r--packages/frontend/src/components/MkNoteHeader.vue82
-rw-r--r--packages/frontend/src/components/global/MkAcct.vue13
-rw-r--r--packages/frontend/src/components/global/MkAvatar.vue112
-rw-r--r--packages/frontend/src/components/global/MkEmoji.vue42
5 files changed, 376 insertions, 431 deletions
diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue
index 45aba1d24b..54afae952c 100644
--- a/packages/frontend/src/components/MkNote.vue
+++ b/packages/frontend/src/components/MkNote.vue
@@ -4,27 +4,26 @@
v-show="!isDeleted"
ref="el"
v-hotkey="keymap"
- class="tkcbzcuz"
+ :class="[$style.root, { [$style.isRenote]: isRenote }]"
:tabindex="!isDeleted ? '-1' : null"
- :class="{ renote: isRenote }"
>
- <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/>
- <div v-if="pinned" class="info"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
- <div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>
- <div v-if="appearNote._featuredId_" class="info"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>
- <div v-if="isRenote" class="renote">
- <MkAvatar v-once class="avatar" :user="note.user"/>
- <i class="ti ti-repeat"></i>
- <I18n :src="i18n.ts.renotedBy" tag="span">
+ <MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/>
+ <div v-if="pinned" :class="$style.tip"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
+ <!--<div v-if="appearNote._prId_" class="tip"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>-->
+ <!--<div v-if="appearNote._featuredId_" class="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>-->
+ <div v-if="isRenote" :class="$style.renote">
+ <MkAvatar v-once :class="$style.renoteAvatar" :user="note.user"/>
+ <i class="ti ti-repeat" style="margin-right: 4px;"></i>
+ <I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText">
<template #user>
- <MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)">
+ <MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
<MkUserName :user="note.user"/>
</MkA>
</template>
</I18n>
- <div class="info">
- <button ref="renoteTime" class="_button time" @click="showRenoteMenu()">
- <i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i>
+ <div :class="$style.renoteInfo">
+ <button ref="renoteTime" :class="$style.renoteTime" class="_button" @click="showRenoteMenu()">
+ <i v-if="isMyRenote" class="ti ti-dots" :class="$style.renoteMenu"></i>
<MkTime :time="note.createdAt"/>
</button>
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
@@ -35,80 +34,80 @@
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
</div>
</div>
- <article class="article" @contextmenu.stop="onContextmenu">
- <MkAvatar v-once class="avatar" :user="appearNote.user"/>
- <div class="main">
- <MkNoteHeader class="header" :note="appearNote" :mini="true"/>
- <MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
- <div class="body">
- <p v-if="appearNote.cw != null" class="cw">
- <Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i"/>
+ <article :class="$style.article" @contextmenu.stop="onContextmenu">
+ <MkAvatar v-once :class="$style.avatar" :user="appearNote.user"/>
+ <div :class="$style.main">
+ <MkNoteHeader :class="$style.header" :note="appearNote" :mini="true"/>
+ <MkInstanceTicker v-if="showTicker" :class="$style.ticker" :instance="appearNote.user.instance"/>
+ <div :class="$style.body">
+ <p v-if="appearNote.cw != null" :class="$style.cw">
+ <Mfm v-if="appearNote.cw != ''" :class="$style.cwText" :text="appearNote.cw" :author="appearNote.user" :i="$i"/>
<MkCwButton v-model="showContent" :note="appearNote"/>
</p>
- <div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed, isLong }">
- <div class="text">
+ <div v-show="appearNote.cw == null || showContent" :class="[$style.content, { [$style.contentCollapsed]: collapsed, [$style.contentIsLong]: isLong }]">
+ <div :class="$style.text">
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
- <MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
+ <MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
<Mfm v-if="appearNote.text" v-once :text="appearNote.text" :author="appearNote.user" :i="$i"/>
- <a v-if="appearNote.renote != null" class="rp">RN:</a>
- <div v-if="translating || translation" class="translation">
+ <div v-if="translating || translation" :class="$style.translation">
<MkLoading v-if="translating" mini/>
- <div v-else class="translated">
+ <div v-else :class="$style.translated">
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}: </b>
<Mfm :text="translation.text" :author="appearNote.user" :i="$i"/>
</div>
</div>
</div>
- <div v-if="appearNote.files.length > 0" class="files">
+ <div v-if="appearNote.files.length > 0" :class="$style.files">
<MkMediaList :media-list="appearNote.files"/>
</div>
- <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/>
- <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/>
- <div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div>
- <button v-if="isLong && collapsed" class="fade _button" @click="collapsed = false">
- <span>{{ i18n.ts.showMore }}</span>
+ <MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" :class="$style.poll"/>
+ <MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
+ <div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
+ <button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
+ <span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
</button>
- <button v-else-if="isLong && !collapsed" class="showLess _button" @click="collapsed = true">
- <span>{{ i18n.ts.showLess }}</span>
+ <button v-else-if="isLong && !collapsed" :class="$style.showLess" class="_button" @click="collapsed = true">
+ <span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span>
</button>
</div>
- <MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
+ <MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
</div>
- <footer class="footer">
+ <footer :class="$style.footer">
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
- <button class="button _button" @click="reply()">
+ <button :class="$style.footerButton" class="_button" @click="reply()">
<i class="ti ti-arrow-back-up"></i>
- <p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p>
+ <p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
</button>
<button
v-if="canRenote"
ref="renoteButton"
- class="button _button"
+ :class="$style.footerButton"
+ class="_button"
@mousedown="renote()"
>
<i class="ti ti-repeat"></i>
- <p v-if="appearNote.renoteCount > 0" class="count">{{ appearNote.renoteCount }}</p>
+ <p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
</button>
- <button v-else class="button _button" disabled>
+ <button v-else :class="$style.footerButton" class="_button" disabled>
<i class="ti ti-ban"></i>
</button>
- <button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()">
+ <button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
<i class="ti ti-plus"></i>
</button>
- <button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
+ <button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
<i class="ti ti-minus"></i>
</button>
- <button ref="menuButton" class="button _button" @mousedown="menu()">
+ <button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown="menu()">
<i class="ti ti-dots"></i>
</button>
</footer>
</div>
</article>
</div>
-<div v-else class="muted" @click="muted = false">
+<div v-else :class="$style.muted" @click="muted = false">
<I18n :src="i18n.ts.userSaysSomething" tag="small">
<template #name>
- <MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)">
+ <MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
<MkUserName :user="appearNote.user"/>
</MkA>
</template>
@@ -349,8 +348,8 @@ function readPromo() {
}
</script>
-<style lang="scss" scoped>
-.tkcbzcuz {
+<style lang="scss" module>
+.root {
position: relative;
transition: box-shadow 0.1s ease;
font-size: 1.05em;
@@ -387,322 +386,273 @@ function readPromo() {
}
}
- &:hover > .article > .main > .footer > .button {
+ &:hover > .article > .main > .footer > .footerButton {
opacity: 1;
}
+}
- > .info {
- display: flex;
- align-items: center;
- padding: 16px 32px 8px 32px;
- line-height: 24px;
- font-size: 90%;
- white-space: pre;
- color: #d28a3f;
-
- > i {
- margin-right: 4px;
- }
-
- > .hide {
- margin-left: auto;
- color: inherit;
- }
- }
-
- > .info + .article {
- padding-top: 8px;
- }
-
- > .reply-to {
- opacity: 0.7;
- padding-bottom: 0;
- }
-
- > .renote {
- display: flex;
- align-items: center;
- padding: 16px 32px 8px 32px;
- line-height: 28px;
- white-space: pre;
- color: var(--renote);
+.tip {
+ display: flex;
+ align-items: center;
+ padding: 16px 32px 8px 32px;
+ line-height: 24px;
+ font-size: 90%;
+ white-space: pre;
+ color: #d28a3f;
+}
- > .avatar {
- flex-shrink: 0;
- display: inline-block;
- width: 28px;
- height: 28px;
- margin: 0 8px 0 0;
- border-radius: 6px;
- }
+.tip + .article {
+ padding-top: 8px;
+}
- > i {
- margin-right: 4px;
- }
+.replyTo {
+ opacity: 0.7;
+ padding-bottom: 0;
+}
- > span {
- overflow: hidden;
- flex-shrink: 1;
- text-overflow: ellipsis;
- white-space: nowrap;
+.renote {
+ display: flex;
+ align-items: center;
+ padding: 16px 32px 8px 32px;
+ line-height: 28px;
+ white-space: pre;
+ color: var(--renote);
+}
- > .name {
- font-weight: bold;
- }
- }
+.renoteAvatar {
+ flex-shrink: 0;
+ display: inline-block;
+ width: 28px;
+ height: 28px;
+ margin: 0 8px 0 0;
+ border-radius: 6px;
+}
- > .info {
- margin-left: auto;
- font-size: 0.9em;
+.renoteText {
+ overflow: hidden;
+ flex-shrink: 1;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
- > .time {
- flex-shrink: 0;
- color: inherit;
+.renoteUserName {
+ font-weight: bold;
+}
- > .dropdownIcon {
- margin-right: 4px;
- }
- }
- }
- }
+.renoteInfo {
+ margin-left: auto;
+ font-size: 0.9em;
+}
- > .renote + .article {
- padding-top: 8px;
- }
+.renoteTime {
+ flex-shrink: 0;
+ color: inherit;
+}
- > .article {
- display: flex;
- padding: 28px 32px 18px;
+.renoteMenu {
+ margin-right: 4px;
+}
- > .avatar {
- flex-shrink: 0;
- display: block;
- margin: 0 14px 8px 0;
- width: 58px;
- height: 58px;
- position: sticky;
- top: calc(22px + var(--stickyTop, 0px));
- left: 0;
- }
+.renoteInfo + .article {
+ padding-top: 8px;
+}
- > .main {
- flex: 1;
- min-width: 0;
+.article {
+ display: flex;
+ padding: 28px 32px 18px;
+}
- > .body {
- container-type: inline-size;
+.avatar {
+ flex-shrink: 0;
+ display: block;
+ margin: 0 14px 8px 0;
+ width: 58px;
+ height: 58px;
+ position: sticky;
+ top: calc(22px + var(--stickyTop, 0px));
+ left: 0;
+}
- > .cw {
- cursor: default;
- display: block;
- margin: 0;
- padding: 0;
- overflow-wrap: break-word;
+.main {
+ flex: 1;
+ min-width: 0;
+}
- > .text {
- margin-right: 8px;
- }
- }
+.body {
+ container-type: inline-size;
+}
- > .content {
- &.isLong {
- > .showLess {
- width: 100%;
- margin-top: 1em;
- position: sticky;
- bottom: 1em;
+.cw {
+ cursor: default;
+ display: block;
+ margin: 0;
+ padding: 0;
+ overflow-wrap: break-word;
+}
- > span {
- display: inline-block;
- background: var(--popup);
- padding: 6px 10px;
- font-size: 0.8em;
- border-radius: 999px;
- box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
- }
- }
- }
+.cwText {
+ margin-right: 8px;
+}
- &.collapsed {
- position: relative;
- max-height: 9em;
- overflow: clip;
+.content {
+}
- > .fade {
- display: block;
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 64px;
- background: linear-gradient(0deg, var(--panel), var(--X15));
+.contentIsLong {
+}
- > span {
- display: inline-block;
- background: var(--panel);
- padding: 6px 10px;
- font-size: 0.8em;
- border-radius: 999px;
- box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
- }
+.showLess {
+ width: 100%;
+ margin-top: 1em;
+ position: sticky;
+ bottom: 1em;
+}
- &:hover {
- > span {
- background: var(--panelHighlight);
- }
- }
- }
- }
+.howLessLabel {
+ display: inline-block;
+ background: var(--popup);
+ padding: 6px 10px;
+ font-size: 0.8em;
+ border-radius: 999px;
+ box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
+}
- > .text {
- overflow-wrap: break-word;
+.contentCollapsed {
+ position: relative;
+ max-height: 9em;
+ overflow: clip;
+}
- > .reply {
- color: var(--accent);
- margin-right: 0.5em;
- }
+.collapsed {
+ display: block;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 64px;
+ background: linear-gradient(0deg, var(--panel), var(--X15));
- > .rp {
- margin-left: 4px;
- font-style: oblique;
- color: var(--renote);
- }
+ &:hover > .collapsedLabel {
+ background: var(--panelHighlight);
+ }
+}
- > .translation {
- border: solid 0.5px var(--divider);
- border-radius: var(--radius);
- padding: 12px;
- margin-top: 8px;
- }
- }
+.collapsedLabel {
+ display: inline-block;
+ background: var(--panel);
+ padding: 6px 10px;
+ font-size: 0.8em;
+ border-radius: 999px;
+ box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
+}
- > .url-preview {
- margin-top: 8px;
- }
+.text {
+ overflow-wrap: break-word;
+}
- > .poll {
- font-size: 80%;
- }
+.replyIcon {
+ color: var(--accent);
+ margin-right: 0.5em;
+}
- > .renote {
- padding: 8px 0;
+.translation {
+ border: solid 0.5px var(--divider);
+ border-radius: var(--radius);
+ padding: 12px;
+ margin-top: 8px;
+}
- > .note {
- padding: 16px;
- border: dashed 1px var(--renote);
- border-radius: 8px;
- }
- }
- }
+.urlPreview {
+ margin-top: 8px;
+}
- > .channel {
- opacity: 0.7;
- font-size: 80%;
- }
- }
+.poll {
+ font-size: 80%;
+}
- > .footer {
- > .button {
- margin: 0;
- padding: 8px;
- opacity: 0.7;
+.quote {
+ padding: 8px 0;
+}
- &:not(:last-child) {
- margin-right: 28px;
- }
+.quoteNote {
+ padding: 16px;
+ border: dashed 1px var(--renote);
+ border-radius: 8px;
+}
- &:hover {
- color: var(--fgHighlighted);
- }
+.channel {
+ opacity: 0.7;
+ font-size: 80%;
+}
- > .count {
- display: inline;
- margin: 0 0 0 8px;
- opacity: 0.7;
- }
+.footerButton {
+ margin: 0;
+ padding: 8px;
+ opacity: 0.7;
- &.reacted {
- color: var(--accent);
- }
- }
- }
- }
+ &:not(:last-child) {
+ margin-right: 28px;
}
- > .reply {
- border-top: solid 0.5px var(--divider);
+ &:hover {
+ color: var(--fgHighlighted);
}
}
+.footerButtonCount {
+ display: inline;
+ margin: 0 0 0 8px;
+ opacity: 0.7;
+}
+
@container (max-width: 500px) {
- .tkcbzcuz {
+ .root {
font-size: 0.9em;
+ }
- > .article {
- > .avatar {
- width: 50px;
- height: 50px;
- }
- }
+ .avatar {
+ width: 50px;
+ height: 50px;
}
}
@container (max-width: 450px) {
- .tkcbzcuz {
- > .renote {
- padding: 8px 16px 0 16px;
- }
+ .renote {
+ padding: 8px 16px 0 16px;
+ }
- > .info {
- padding: 8px 16px 0 16px;
- }
+ .tip {
+ padding: 8px 16px 0 16px;
+ }
- > .article {
- padding: 14px 16px 9px;
+ .article {
+ padding: 14px 16px 9px;
+ }
- > .avatar {
- margin: 0 10px 8px 0;
- width: 46px;
- height: 46px;
- top: calc(14px + var(--stickyTop, 0px));
- }
- }
+ .avatar {
+ margin: 0 10px 8px 0;
+ width: 46px;
+ height: 46px;
+ top: calc(14px + var(--stickyTop, 0px));
}
}
@container (max-width: 350px) {
- .tkcbzcuz {
- > .article {
- > .main {
- > .footer {
- > .button {
- &:not(:last-child) {
- margin-right: 18px;
- }
- }
- }
- }
+ .footerButton {
+ &:not(:last-child) {
+ margin-right: 18px;
}
}
}
@container (max-width: 300px) {
- .tkcbzcuz {
- > .article {
- > .avatar {
- width: 44px;
- height: 44px;
- }
+ .avatar {
+ width: 44px;
+ height: 44px;
+ }
- > .main {
- > .footer {
- > .button {
- &:not(:last-child) {
- margin-right: 12px;
- }
- }
- }
- }
+ .footerButton {
+ &:not(:last-child) {
+ margin-right: 12px;
}
}
}
diff --git a/packages/frontend/src/components/MkNoteHeader.vue b/packages/frontend/src/components/MkNoteHeader.vue
index 38bd33ff74..8771168a42 100644
--- a/packages/frontend/src/components/MkNoteHeader.vue
+++ b/packages/frontend/src/components/MkNoteHeader.vue
@@ -1,12 +1,12 @@
<template>
-<header class="kkwtjztg">
- <MkA v-once v-user-preview="note.user.id" class="name" :to="userPage(note.user)">
+<header :class="$style.root">
+ <MkA v-once v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)">
<MkUserName :user="note.user"/>
</MkA>
- <div v-if="note.user.isBot" class="is-bot">bot</div>
- <div class="username"><MkAcct :user="note.user"/></div>
- <div class="info">
- <MkA class="created-at" :to="notePage(note)">
+ <div v-if="note.user.isBot" :class="$style.isBot">bot</div>
+ <div :class="$style.username"><MkAcct :user="note.user"/></div>
+ <div :class="$style.info">
+ <MkA :to="notePage(note)">
<MkTime :time="note.createdAt"/>
</MkA>
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
@@ -32,49 +32,49 @@ defineProps<{
}>();
</script>
-<style lang="scss" scoped>
-.kkwtjztg {
+<style lang="scss" module>
+.root {
display: flex;
align-items: baseline;
white-space: nowrap;
+}
- > .name {
- flex-shrink: 1;
- display: block;
- margin: 0 .5em 0 0;
- padding: 0;
- overflow: hidden;
- font-size: 1em;
- font-weight: bold;
- text-decoration: none;
- text-overflow: ellipsis;
+.name {
+ flex-shrink: 1;
+ display: block;
+ margin: 0 .5em 0 0;
+ padding: 0;
+ overflow: hidden;
+ font-size: 1em;
+ font-weight: bold;
+ text-decoration: none;
+ text-overflow: ellipsis;
- &:hover {
- text-decoration: underline;
- }
+ &:hover {
+ text-decoration: underline;
}
+}
- > .is-bot {
- flex-shrink: 0;
- align-self: center;
- margin: 0 .5em 0 0;
- padding: 1px 6px;
- font-size: 80%;
- border: solid 0.5px var(--divider);
- border-radius: 3px;
- }
+.isBot {
+ flex-shrink: 0;
+ align-self: center;
+ margin: 0 .5em 0 0;
+ padding: 1px 6px;
+ font-size: 80%;
+ border: solid 0.5px var(--divider);
+ border-radius: 3px;
+}
- > .username {
- flex-shrink: 9999999;
- margin: 0 .5em 0 0;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+.username {
+ flex-shrink: 9999999;
+ margin: 0 .5em 0 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
- > .info {
- flex-shrink: 0;
- margin-left: auto;
- font-size: 0.9em;
- }
+.info {
+ flex-shrink: 0;
+ margin-left: auto;
+ font-size: 0.9em;
}
</style>
diff --git a/packages/frontend/src/components/global/MkAcct.vue b/packages/frontend/src/components/global/MkAcct.vue
index c3e806b5fb..2a43ded9e1 100644
--- a/packages/frontend/src/components/global/MkAcct.vue
+++ b/packages/frontend/src/components/global/MkAcct.vue
@@ -1,7 +1,7 @@
<template>
-<span class="mk-acct">
- <span class="name">@{{ user.username }}</span>
- <span v-if="user.host || detail || $store.state.showFullAcct" class="host">@{{ user.host || host }}</span>
+<span>
+ <span>@{{ user.username }}</span>
+ <span v-if="user.host || detail || $store.state.showFullAcct" style="opacity: 0.5;">@{{ user.host || host }}</span>
</span>
</template>
@@ -18,10 +18,3 @@ defineProps<{
const host = toUnicode(hostRaw);
</script>
-<style lang="scss" scoped>
-.mk-acct {
- > .host {
- opacity: 0.5;
- }
-}
-</style>
diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue
index 2f8e7945fc..0a42a29323 100644
--- a/packages/frontend/src/components/global/MkAvatar.vue
+++ b/packages/frontend/src/components/global/MkAvatar.vue
@@ -1,11 +1,11 @@
<template>
-<span v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" class="eiwwqkts _noSelect" :class="{ cat: user.isCat, square: $store.state.squareAvatars }" :style="{ color }" :title="acct(user)" @click="onClick">
- <img class="inner" :src="url" decoding="async"/>
- <MkUserOnlineIndicator v-if="showIndicator" class="indicator" :user="user"/>
+<span v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" class="_noSelect" :style="{ color }" :title="acct(user)" @click="onClick">
+ <img :class="$style.inner" :src="url" decoding="async"/>
+ <MkUserOnlineIndicator v-if="showIndicator" :class="$style.indicator" :user="user"/>
</span>
-<MkA v-else v-user-preview="disablePreview ? undefined : user.id" class="eiwwqkts _noSelect" :class="{ cat: user.isCat, square: $store.state.squareAvatars }" :style="{ color }" :to="userPage(user)" :title="acct(user)" :target="target">
- <img class="inner" :src="url" decoding="async"/>
- <MkUserOnlineIndicator v-if="showIndicator" class="indicator" :user="user"/>
+<MkA v-else v-user-preview="disablePreview ? undefined : user.id" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :to="userPage(user)" :title="acct(user)" :target="target">
+ <img :class="$style.inner" :src="url" decoding="async"/>
+ <MkUserOnlineIndicator v-if="showIndicator" :class="$style.indicator" :user="user"/>
</MkA>
</template>
@@ -68,75 +68,77 @@ watch(() => props.user.avatarBlurhash, () => {
75% { transform: rotate(0deg) skew(-30deg); }
to { transform: rotate(-37.6deg) skew(-30deg); }
}
+</style>
-.eiwwqkts {
+<style lang="scss" module>
+.root {
position: relative;
display: inline-block;
vertical-align: bottom;
flex-shrink: 0;
border-radius: 100%;
line-height: 16px;
+}
+
+.inner {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ top: 0;
+ border-radius: 100%;
+ z-index: 1;
+ overflow: clip;
+ object-fit: cover;
+ width: 100%;
+ height: 100%;
+}
+
+.indicator {
+ position: absolute;
+ z-index: 1;
+ bottom: 0;
+ left: 0;
+ width: 20%;
+ height: 20%;
+}
+
+.square {
+ border-radius: 20%;
> .inner {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- top: 0;
- border-radius: 100%;
- z-index: 1;
- overflow: clip;
- object-fit: cover;
- width: 100%;
- height: 100%;
+ border-radius: 20%;
}
+}
- > .indicator {
- position: absolute;
- z-index: 1;
- bottom: 0;
- left: 0;
- width: 20%;
- height: 20%;
+.cat {
+ &:before, &:after {
+ background: #df548f;
+ border: solid 4px currentColor;
+ box-sizing: border-box;
+ content: '';
+ display: inline-block;
+ height: 50%;
+ width: 50%;
}
- &.square {
- border-radius: 20%;
-
- > .inner {
- border-radius: 20%;
- }
+ &:before {
+ border-radius: 0 75% 75%;
+ transform: rotate(37.5deg) skew(30deg);
}
- &.cat {
- &:before, &:after {
- background: #df548f;
- border: solid 4px currentColor;
- box-sizing: border-box;
- content: '';
- display: inline-block;
- height: 50%;
- width: 50%;
- }
+ &:after {
+ border-radius: 75% 0 75% 75%;
+ transform: rotate(-37.5deg) skew(-30deg);
+ }
+ &:hover {
&:before {
- border-radius: 0 75% 75%;
- transform: rotate(37.5deg) skew(30deg);
+ animation: earwiggleleft 1s infinite;
}
&:after {
- border-radius: 75% 0 75% 75%;
- transform: rotate(-37.5deg) skew(-30deg);
- }
-
- &:hover {
- &:before {
- animation: earwiggleleft 1s infinite;
- }
-
- &:after {
- animation: earwiggleright 1s infinite;
- }
+ animation: earwiggleright 1s infinite;
}
}
}
diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue
index 67e9ef428a..bc88cf3be4 100644
--- a/packages/frontend/src/components/global/MkEmoji.vue
+++ b/packages/frontend/src/components/global/MkEmoji.vue
@@ -1,6 +1,6 @@
<template>
-<img v-if="isCustom" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/>
-<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" decoding="async" @pointerenter="computeTitle"/>
+<img v-if="isCustom" :class="[$style.root, $style.custom, { [$style.normal]: normal, [$style.noStyle]: noStyle }]" :src="url" :alt="alt" :title="alt" decoding="async"/>
+<img v-else-if="char && !useOsNativeEmojis" :class="$style.root" :src="url" :alt="alt" decoding="async" @pointerenter="computeTitle"/>
<span v-else-if="char && useOsNativeEmojis" :alt="alt" @pointerenter="computeTitle">{{ char }}</span>
<span v-else>{{ emoji }}</span>
</template>
@@ -47,32 +47,32 @@ function computeTitle(event: PointerEvent): void {
}
</script>
-<style lang="scss" scoped>
-.mk-emoji {
+<style lang="scss" module>
+.root {
height: 1.25em;
vertical-align: -0.25em;
+}
- &.custom {
- height: 2.5em;
- vertical-align: middle;
- transition: transform 0.2s ease;
+.custom {
+ height: 2.5em;
+ vertical-align: middle;
+ transition: transform 0.2s ease;
- &:hover {
- transform: scale(1.2);
- }
+ &:hover {
+ transform: scale(1.2);
+ }
+}
- &.normal {
- height: 1.25em;
- vertical-align: -0.25em;
+.normal {
+ height: 1.25em;
+ vertical-align: -0.25em;
- &:hover {
- transform: none;
- }
- }
+ &:hover {
+ transform: none;
}
+}
- &.noStyle {
- height: auto !important;
- }
+.noStyle {
+ height: auto !important;
}
</style>