diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-08-17 22:01:46 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-08-17 22:01:46 +0900 |
| commit | df67836c1ad281d2622b52bdf7c767b2dfc0e6a5 (patch) | |
| tree | 5a2c4e5b681857d846d5fea1f4058b72e80651da /src/client/components | |
| parent | Merge branch 'develop' (diff) | |
| parent | Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop (diff) | |
| download | misskey-df67836c1ad281d2622b52bdf7c767b2dfc0e6a5.tar.gz misskey-df67836c1ad281d2622b52bdf7c767b2dfc0e6a5.tar.bz2 misskey-df67836c1ad281d2622b52bdf7c767b2dfc0e6a5.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/client/components')
| -rw-r--r-- | src/client/components/date-separated-list.vue | 4 | ||||
| -rw-r--r-- | src/client/components/global/loading.vue | 32 | ||||
| -rw-r--r-- | src/client/components/note-detailed.vue | 40 | ||||
| -rw-r--r-- | src/client/components/note.vue | 32 | ||||
| -rw-r--r-- | src/client/components/notes.vue | 23 | ||||
| -rw-r--r-- | src/client/components/post-form.vue | 4 | ||||
| -rwxr-xr-x | src/client/components/signin.vue | 4 | ||||
| -rw-r--r-- | src/client/components/signup.vue | 8 | ||||
| -rw-r--r-- | src/client/components/ui/popup.vue | 2 | ||||
| -rw-r--r-- | src/client/components/updated.vue | 58 |
10 files changed, 173 insertions, 34 deletions
diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue index 7a4cc5ef98..fa0b6d669c 100644 --- a/src/client/components/date-separated-list.vue +++ b/src/client/components/date-separated-list.vue @@ -93,13 +93,13 @@ export default defineComponent({ }); return h(this.$store.state.animation ? TransitionGroup : 'div', this.$store.state.animation ? { - class: 'sqadhkmv' + (this.noGap ? ' noGap _block' : ''), + class: 'sqadhkmv' + (this.noGap ? ' noGap' : ''), name: 'list', tag: 'div', 'data-direction': this.direction, 'data-reversed': this.reversed ? 'true' : 'false', } : { - class: 'sqadhkmv' + (this.noGap ? ' noGap _block' : ''), + class: 'sqadhkmv' + (this.noGap ? ' noGap' : ''), }, { default: renderChildren }); diff --git a/src/client/components/global/loading.vue b/src/client/components/global/loading.vue index 9b810f0a16..7bde53c12e 100644 --- a/src/client/components/global/loading.vue +++ b/src/client/components/global/loading.vue @@ -1,5 +1,5 @@ <template> -<div class="yxspomdl" :class="{ inline, colored }"> +<div class="yxspomdl" :class="{ inline, colored, mini }"> <div class="ring"></div> </div> </template> @@ -18,7 +18,12 @@ export default defineComponent({ type: Boolean, required: false, default: true - } + }, + mini: { + type: Boolean, + required: false, + default: false + }, } }); </script> @@ -38,6 +43,8 @@ export default defineComponent({ text-align: center; cursor: wait; + --size: 48px; + &.colored { color: var(--accent); } @@ -45,19 +52,12 @@ export default defineComponent({ &.inline { display: inline; padding: 0; + --size: 32px; + } - > .ring:after { - width: 32px; - height: 32px; - } - - > .ring { - &:before, - &:after { - width: 32px; - height: 32px; - } - } + &.mini { + padding: 16px; + --size: 32px; } > .ring { @@ -70,8 +70,8 @@ export default defineComponent({ content: " "; display: block; box-sizing: border-box; - width: 48px; - height: 48px; + width: var(--size); + height: var(--size); border-radius: 50%; border: solid 4px; } diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue index d601052927..e7f116d1fd 100644 --- a/src/client/components/note-detailed.vue +++ b/src/client/components/note-detailed.vue @@ -1,6 +1,6 @@ <template> <div - class="note _block" + class="lxwezrsl _block" v-if="!muted" v-show="!isDeleted" :tabindex="!isDeleted ? '-1' : null" @@ -67,6 +67,13 @@ <MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <a class="rp" v-if="appearNote.renote != null">RN:</a> + <div class="translation" v-if="translating || translation"> + <MkLoading v-if="translating" mini/> + <div class="translated" v-else> + <b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}:</b> + {{ translation.text }} + </div> + </div> </div> <div class="files" v-if="appearNote.files.length > 0"> <XMediaList :media-list="appearNote.files"/> @@ -79,8 +86,8 @@ </div> <footer class="footer"> <div class="info"> - <span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span> - <MkTime class="created-at" :time="note.createdAt" mode="detail"/> + <span class="mobile" v-if="appearNote.viaMobile"><i class="fas fa-mobile-alt"></i></span> + <MkTime class="created-at" :time="appearNote.createdAt" mode="detail"/> </div> <XReactionsViewer :note="appearNote" ref="reactionsViewer"/> <button @click="reply()" class="button _button"> @@ -178,6 +185,8 @@ export default defineComponent({ showContent: false, isDeleted: false, muted: false, + translation: null, + translating: false, }; }, @@ -619,6 +628,11 @@ export default defineComponent({ text: this.$ts.share, action: this.share }, + this.$instance.translatorAvailable ? { + icon: 'fas fa-language', + text: this.$ts.translate, + action: this.translate + } : undefined, null, statePromise.then(state => state.isFavorited ? { icon: 'fas fa-star', @@ -852,6 +866,17 @@ export default defineComponent({ }); }, + async translate() { + if (this.translation != null) return; + this.translating = true; + const res = await os.api('notes/translate', { + noteId: this.appearNote.id, + targetLang: localStorage.getItem('lang') || navigator.language, + }); + this.translating = false; + this.translation = res; + }, + focus() { this.$el.focus(); }, @@ -874,7 +899,7 @@ export default defineComponent({ </script> <style lang="scss" scoped> -.note { +.lxwezrsl { position: relative; transition: box-shadow 0.1s ease; overflow: hidden; @@ -1050,6 +1075,13 @@ export default defineComponent({ font-style: oblique; color: var(--renote); } + + > .translation { + border: solid 0.5px var(--divider); + border-radius: var(--radius); + padding: 12px; + margin-top: 8px; + } } > .url-preview { diff --git a/src/client/components/note.vue b/src/client/components/note.vue index 873b96030a..38b529dd91 100644 --- a/src/client/components/note.vue +++ b/src/client/components/note.vue @@ -51,6 +51,13 @@ <MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA> <Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/> <a class="rp" v-if="appearNote.renote != null">RN:</a> + <div class="translation" v-if="translating || translation"> + <MkLoading v-if="translating" mini/> + <div class="translated" v-else> + <b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}:</b> + {{ translation.text }} + </div> + </div> </div> <div class="files" v-if="appearNote.files.length > 0"> <XMediaList :media-list="appearNote.files"/> @@ -164,6 +171,8 @@ export default defineComponent({ collapsed: false, isDeleted: false, muted: false, + translation: null, + translating: false, }; }, @@ -594,6 +603,11 @@ export default defineComponent({ text: this.$ts.share, action: this.share }, + this.$instance.translatorAvailable ? { + icon: 'fas fa-language', + text: this.$ts.translate, + action: this.translate + } : undefined, null, statePromise.then(state => state.isFavorited ? { icon: 'fas fa-star', @@ -827,6 +841,17 @@ export default defineComponent({ }); }, + async translate() { + if (this.translation != null) return; + this.translating = true; + const res = await os.api('notes/translate', { + noteId: this.appearNote.id, + targetLang: localStorage.getItem('lang') || navigator.language, + }); + this.translating = false; + this.translation = res; + }, + focus() { this.$el.focus(); }, @@ -1053,6 +1078,13 @@ export default defineComponent({ font-style: oblique; color: var(--renote); } + + > .translation { + border: solid 0.5px var(--divider); + border-radius: var(--radius); + padding: 12px; + margin-top: 8px; + } } > .url-preview { diff --git a/src/client/components/notes.vue b/src/client/components/notes.vue index e90102921a..ba3b7d2b39 100644 --- a/src/client/components/notes.vue +++ b/src/client/components/notes.vue @@ -9,7 +9,7 @@ <div>{{ $ts.noNotes }}</div> </div> - <div v-else> + <div v-else class="giivymft" :class="{ noGap }"> <div v-show="more && reversed" style="margin-bottom: var(--margin);"> <MkButton style="margin: 0 auto;" @click="fetchMoreFeature" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> <template v-if="!moreFetching">{{ $ts.loadMore }}</template> @@ -17,8 +17,8 @@ </MkButton> </div> - <XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true"> - <XNote :note="note" class="_block" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/> + <XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :no-gap="noGap" :ad="true" class="notes"> + <XNote class="qtqtichx" :note="note" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/> </XList> <div v-show="more && !reversed" style="margin-top: var(--margin);"> @@ -108,4 +108,21 @@ export default defineComponent({ .fade-leave-to { opacity: 0; } + +.giivymft { + &.noGap { + > .notes { + background: var(--panel); + } + } + + &:not(.noGap) { + > .notes { + .qtqtichx { + background: var(--panel); + border-radius: var(--radius); + } + } + } +} </style> diff --git a/src/client/components/post-form.vue b/src/client/components/post-form.vue index f2c625a556..221dc74313 100644 --- a/src/client/components/post-form.vue +++ b/src/client/components/post-form.vue @@ -17,7 +17,7 @@ <span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span> <span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span> </button> - <button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button> + <button class="submit _buttonPrimary" :disabled="!canPost" @click="post" data-cy-open-post-form-submit>{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button> </div> </header> <div class="form" :class="{ fixed }"> @@ -36,7 +36,7 @@ </div> <MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo> <input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown"> - <textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" /> + <textarea v-model="text" class="text" :class="{ withCw: useCw }" ref="text" :disabled="posting" :placeholder="placeholder" @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd" data-cy-post-form-text/> <input v-show="withHashtags" ref="hashtags" class="hashtags" v-model="hashtags" :placeholder="$ts.hashtags" list="hashtags"> <XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/> <XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/> diff --git a/src/client/components/signin.vue b/src/client/components/signin.vue index f1e5d6afe5..0094038fb6 100755 --- a/src/client/components/signin.vue +++ b/src/client/components/signin.vue @@ -3,11 +3,11 @@ <div class="auth _section"> <div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div> <div class="normal-signin" v-if="!totpLogin"> - <MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange"> + <MkInput v-model="username" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:modelValue="onUsernameChange" data-cy-signin-username> <template #prefix>@</template> <template #suffix>@{{ host }}</template> </MkInput> - <MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required> + <MkInput v-model="password" :placeholder="$ts.password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required data-cy-signin-password> <template #prefix><i class="fas fa-lock"></i></template> <template #caption><button class="_textButton" @click="resetPassword" type="button">{{ $ts.forgotPassword }}</button></template> </MkInput> diff --git a/src/client/components/signup.vue b/src/client/components/signup.vue index 0cdeb633d8..b0b0c2ad4d 100644 --- a/src/client/components/signup.vue +++ b/src/client/components/signup.vue @@ -5,7 +5,7 @@ <template #label>{{ $ts.invitationCode }}</template> <template #prefix><i class="fas fa-key"></i></template> </MkInput> - <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername"> + <MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:modelValue="onChangeUsername" data-cy-signup-username> <template #label>{{ $ts.username }}</template> <template #prefix>@</template> <template #suffix>@{{ host }}</template> @@ -19,7 +19,7 @@ <span v-if="usernameState == 'max-range'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span> </template> </MkInput> - <MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword"> + <MkInput v-model="password" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePassword" data-cy-signup-password> <template #label>{{ $ts.password }}</template> <template #prefix><i class="fas fa-lock"></i></template> <template #caption> @@ -28,7 +28,7 @@ <span v-if="passwordStrength == 'high'" style="color: var(--success)"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</span> </template> </MkInput> - <MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype"> + <MkInput v-model="retypedPassword" type="password" :autocomplete="Math.random()" required @update:modelValue="onChangePasswordRetype" data-cy-signup-password-retype> <template #label>{{ $ts.password }} ({{ $ts.retype }})</template> <template #prefix><i class="fas fa-lock"></i></template> <template #caption> @@ -46,7 +46,7 @@ </label> <captcha v-if="meta.enableHcaptcha" class="captcha" provider="hcaptcha" ref="hcaptcha" v-model:value="hCaptchaResponse" :sitekey="meta.hcaptchaSiteKey"/> <captcha v-if="meta.enableRecaptcha" class="captcha" provider="recaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/> - <MkButton type="submit" :disabled="shouldDisableSubmitting" primary>{{ $ts.start }}</MkButton> + <MkButton type="submit" :disabled="shouldDisableSubmitting" primary data-cy-signup-submit>{{ $ts.start }}</MkButton> </template> </form> </template> diff --git a/src/client/components/ui/popup.vue b/src/client/components/ui/popup.vue index 9e360411c0..8497eedecb 100644 --- a/src/client/components/ui/popup.vue +++ b/src/client/components/ui/popup.vue @@ -1,5 +1,5 @@ <template> -<transition :name="$store.state.animation ? 'popup-menu' : ''" :duration="$store.state.animation ? 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered"> +<transition :name="$store.state.animation ? 'popup-menu' : ''" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered"> <div v-show="manualShowing != null ? manualShowing : showing" class="ccczpooj" :class="{ front, fixed, top: position === 'top' }" ref="content" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <slot :point="point"></slot> </div> diff --git a/src/client/components/updated.vue b/src/client/components/updated.vue new file mode 100644 index 0000000000..5033d866fb --- /dev/null +++ b/src/client/components/updated.vue @@ -0,0 +1,58 @@ +<template> +<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')"> + <div class="ewlycnyt"> + <div class="title">{{ $ts.misskeyUpdated }}</div> + <div class="version">✨{{ version }}🚀</div> + <MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton> + <MkButton primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton> + </div> +</MkModal> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import MkModal from '@client/components/ui/modal.vue'; +import MkButton from '@client/components/ui/button.vue'; +import { version } from '@client/config'; + +export default defineComponent({ + components: { + MkModal, + MkButton, + }, + + data() { + return { + version: version, + }; + }, + + methods: { + whatIsNew() { + this.$refs.modal.close(); + this.$router.push('/docs/general/changelog'); + } + } +}); +</script> + +<style lang="scss" scoped> +.ewlycnyt { + position: relative; + padding: 32px; + min-width: 320px; + max-width: 480px; + box-sizing: border-box; + text-align: center; + background: var(--panel); + border-radius: var(--radius); + + > .title { + font-weight: bold; + } + + > .version { + margin: 1em 0; + } +} +</style> |