kopia lustrzana https://codeberg.org/nmkj/audon
add initial support of i18n
rodzic
4884afbbbb
commit
abee1fa2e9
|
@ -1,12 +1,30 @@
|
||||||
|
# Domain of your Audon server
|
||||||
LOCAL_DOMAIN=audon.example.com
|
LOCAL_DOMAIN=audon.example.com
|
||||||
|
|
||||||
|
#### Database Settings ####
|
||||||
|
# Host of MongoDB, set as [host]:[port]
|
||||||
DB_HOST=db:27017
|
DB_HOST=db:27017
|
||||||
|
# Database name in MongoDB
|
||||||
DB_NAME=audon
|
DB_NAME=audon
|
||||||
|
# Username to connect to MongoDB
|
||||||
DB_USER=mongo
|
DB_USER=mongo
|
||||||
|
# Password to connect to MongoDB
|
||||||
DB_PASS=mongo
|
DB_PASS=mongo
|
||||||
|
|
||||||
|
#### Redis Settings ####
|
||||||
|
# Host of Redis, set as [host]:[port]
|
||||||
REDIS_HOST=redis:6379
|
REDIS_HOST=redis:6379
|
||||||
|
# Username to connect to Redis (optional)
|
||||||
REDIS_USER=
|
REDIS_USER=
|
||||||
|
# Password to connect to Redis (optional)
|
||||||
REDIS_PASS=
|
REDIS_PASS=
|
||||||
|
|
||||||
|
### LiveKit Settings ###
|
||||||
|
# Same as the keys field in livekit.yaml
|
||||||
LIVEKIT_API_KEY=devkey
|
LIVEKIT_API_KEY=devkey
|
||||||
|
# Same as the keys field in livekit.yaml
|
||||||
LIVEKIT_API_SECRET=secret
|
LIVEKIT_API_SECRET=secret
|
||||||
|
# Host of LiveKit, should be a different domain from LOCAL_DOMAIN
|
||||||
LIVEKIT_HOST=livekit.example.com
|
LIVEKIT_HOST=livekit.example.com
|
||||||
|
# This value will be returned by Audon backend to browsers. Set the same domain as LIVEKIT_HOST if you are not sure.
|
||||||
LIVEKIT_LOCAL_DOMAIN=livekit.example.com
|
LIVEKIT_LOCAL_DOMAIN=livekit.example.com
|
||||||
|
|
Plik diff jest za duży
Load Diff
|
@ -9,6 +9,7 @@
|
||||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@intlify/unplugin-vue-i18n": "^0.8.1",
|
||||||
"@vuelidate/core": "^2.0.0",
|
"@vuelidate/core": "^2.0.0",
|
||||||
"@vuelidate/validators": "^2.0.0",
|
"@vuelidate/validators": "^2.0.0",
|
||||||
"@vueuse/core": "^9.6.0",
|
"@vueuse/core": "^9.6.0",
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
"masto": "^4.9.0",
|
"masto": "^4.9.0",
|
||||||
"pinia": "^2.0.26",
|
"pinia": "^2.0.26",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
"vuetify": "^3.0.3"
|
"vuetify": "^3.0.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,20 +1,40 @@
|
||||||
<script setup>
|
<script>
|
||||||
import { RouterView, RouterLink } from 'vue-router'
|
import { RouterView, RouterLink } from "vue-router";
|
||||||
|
import locales from "./locales"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
return {
|
||||||
|
locales
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onLocaleChange() {
|
||||||
|
localStorage.setItem("locale", this.$i18n.locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-app class="fill-height">
|
<v-app class="fill-height">
|
||||||
<v-system-bar window>
|
<v-system-bar window>
|
||||||
<v-row>
|
<h2 class="text-center w-100">
|
||||||
<v-col class="text-center">
|
<RouterLink
|
||||||
<h2><RouterLink :to="{name: 'home'}" style="text-decoration: inherit; color: inherit;">Audon</RouterLink></h2>
|
:to="{ name: 'home' }"
|
||||||
</v-col>
|
style="text-decoration: inherit; color: inherit;"
|
||||||
</v-row>
|
>Audon</RouterLink
|
||||||
<div style="position:fixed">v0.1.0-dev3</div>
|
>
|
||||||
|
</h2>
|
||||||
</v-system-bar>
|
</v-system-bar>
|
||||||
<v-main>
|
<v-main>
|
||||||
<v-container class="fill-height">
|
<v-container class="fill-height">
|
||||||
<v-row align="center" justify="center" class="fill-height" id="mainArea">
|
<v-row
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
class="fill-height"
|
||||||
|
id="mainArea"
|
||||||
|
>
|
||||||
<v-col>
|
<v-col>
|
||||||
<v-responsive class="mx-auto" max-width="600px">
|
<v-responsive class="mx-auto" max-width="600px">
|
||||||
<RouterView />
|
<RouterView />
|
||||||
|
@ -23,6 +43,22 @@ import { RouterView, RouterLink } from 'vue-router'
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
</v-main>
|
</v-main>
|
||||||
|
<v-bottom-navigation :height="30">
|
||||||
|
<div class="w-100 d-flex justify-space-between align-center px-3">
|
||||||
|
<div>v0.1.0-dev3</div>
|
||||||
|
<div>
|
||||||
|
<select v-model="$i18n.locale" id="localeSelector" @change="onLocaleChange">
|
||||||
|
<option
|
||||||
|
v-for="locale in $i18n.availableLocales"
|
||||||
|
:key="`locale-${locale}`"
|
||||||
|
:value="locale"
|
||||||
|
>
|
||||||
|
{{ locales[locale] }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-bottom-navigation>
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -30,4 +66,9 @@ import { RouterView, RouterLink } from 'vue-router'
|
||||||
#app .v-application__wrap {
|
#app .v-application__wrap {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#localeSelector option {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
about: "What is Audon?"
|
||||||
|
back: "Back"
|
||||||
|
login: "Sign In"
|
||||||
|
logout: "Sign out"
|
||||||
|
logoutConfirm: "Are you sure you want to sign out from Audon?"
|
||||||
|
loginRequired: "You need to sign in to view this page."
|
||||||
|
create: "Create"
|
||||||
|
cancel: "Cancel"
|
||||||
|
edit: "Edit"
|
||||||
|
save: "Save"
|
||||||
|
share: "Share"
|
||||||
|
copy: "Copy"
|
||||||
|
copied: "Copied"
|
||||||
|
enterRoom: "Enter"
|
||||||
|
leaveRoom: "Leave"
|
||||||
|
closeRoom: "Close"
|
||||||
|
close: "Close"
|
||||||
|
server: "Your Mastodon server"
|
||||||
|
addressRequired: "Enter your server address"
|
||||||
|
invalidAddress: "Invalid address"
|
||||||
|
serverNotFound: "Server not found"
|
||||||
|
createNewRoom: "Create New Room"
|
||||||
|
editRoom: "Edit Room"
|
||||||
|
comingFuture: "Coming with future update!"
|
||||||
|
form:
|
||||||
|
title: "Title"
|
||||||
|
titleRequired: "Room title required"
|
||||||
|
description: "Description"
|
||||||
|
restriction: "Who can join"
|
||||||
|
cohosts: "Cohosts"
|
||||||
|
cohostCanAlwaysJoin: "Cohosts can join regardless of this setting."
|
||||||
|
schedule: "Schedule at"
|
||||||
|
relationships:
|
||||||
|
everyone: "Everyone"
|
||||||
|
following: "Your following accounts"
|
||||||
|
follower: "Your follower accounts"
|
||||||
|
knowing: "Your following or follower accounts"
|
||||||
|
mutual: "Your mutual-follow accounts"
|
||||||
|
private: "Cohosts only"
|
||||||
|
shareRoomMessage: "Join my Audon room!\n{link}\n\nTitle: {title}"
|
||||||
|
roomReady:
|
||||||
|
header: "Your room is ready!"
|
||||||
|
message: "Your room \"{title}\" is now ready. Share the following URL with other participants."
|
||||||
|
errors:
|
||||||
|
notFound: "{value} not found"
|
||||||
|
alreadyAdded: "Already added"
|
||||||
|
connectionFailed: "Failed to connect"
|
||||||
|
alreadyConnected: "You have already joined this room on another device. Please wait for a minute to recoonect."
|
||||||
|
alreadyClosed: "This room has already been closed."
|
||||||
|
restriction:
|
||||||
|
following: "Only host's following accounts can join."
|
||||||
|
follower: "Only host's follower accounts can join."
|
||||||
|
knowing: "Only host's following or follower accounts can join."
|
||||||
|
mutual: "Only hots's mutual-follow accounts can join."
|
||||||
|
private: "Only cohosts can join."
|
||||||
|
default: "You are not allowed to join."
|
||||||
|
startListening: "Start Listening"
|
||||||
|
browserMuted: "Your sound is muted by the browser. Press @:startListening to continue."
|
||||||
|
speakRequest:
|
||||||
|
label: "Speak Requests"
|
||||||
|
dialog: "Are you sure you want to send a request to be a speaker?"
|
||||||
|
norequest: "No request"
|
||||||
|
sent: "Request sent!"
|
||||||
|
receive: "New speak request received!"
|
||||||
|
microphoneBlocked: "Your browser blocked recording."
|
||||||
|
closeRoomConfirm: "Are you sure you want to close this room?"
|
||||||
|
roomEvent:
|
||||||
|
closedByHost: "Host has closed this room."
|
||||||
|
removed: "You have been requested to leave."
|
|
@ -0,0 +1,7 @@
|
||||||
|
// This defines display names of locales for the language selector in App.vue.
|
||||||
|
// Keys must match the file names of *.yaml in src/locales.
|
||||||
|
|
||||||
|
export default {
|
||||||
|
en: "English",
|
||||||
|
ja: "日本語"
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
about: "Audonについて"
|
||||||
|
back: "戻る"
|
||||||
|
login: "ログイン"
|
||||||
|
logout: "ログアウト"
|
||||||
|
logoutConfirm: "Audon からログアウトしますか?"
|
||||||
|
loginRequired: "続行するにはログインする必要があります。"
|
||||||
|
create: "作成"
|
||||||
|
cancel: "キャンセル"
|
||||||
|
edit: "編集"
|
||||||
|
save: "保存"
|
||||||
|
copy: "コピー"
|
||||||
|
copied: "コピーしました"
|
||||||
|
enterRoom: "入室"
|
||||||
|
leaveRoom: "退室"
|
||||||
|
closeRoom: "閉室"
|
||||||
|
close: "閉じる"
|
||||||
|
server: "Mastodon サーバー"
|
||||||
|
addressRequired: "アドレスを入力してください"
|
||||||
|
invalidAddress: "アドレスが有効ではありません"
|
||||||
|
serverNotFound: "サーバーが見つかりません"
|
||||||
|
createNewRoom: "部屋を作成"
|
||||||
|
editRoom: "部屋の編集"
|
||||||
|
comingFuture: "今後のアップデートで追加予定"
|
||||||
|
form:
|
||||||
|
title: "タイトル"
|
||||||
|
titleRequired: "部屋の名前を入力してください"
|
||||||
|
description: "説明"
|
||||||
|
restriction: "入室制限"
|
||||||
|
cohosts: "共同ホスト"
|
||||||
|
cohostCanAlwaysJoin: "共同ホストは制限に関わらず入室できます。"
|
||||||
|
schedule: "開始予約"
|
||||||
|
relationships:
|
||||||
|
everyone: "制限なし"
|
||||||
|
following: "あなたのフォロー限定"
|
||||||
|
follower: "あなたのフォロワー限定"
|
||||||
|
knowing: "あなたのフォローまたはフォロワー限定"
|
||||||
|
mutual: "あなたの相互フォロー限定"
|
||||||
|
private: "共同ホスト限定"
|
||||||
|
shareRoomMessage: "Audon で部屋を作りました!\n参加用リンク: {link}\nタイトル: {title}"
|
||||||
|
roomReady:
|
||||||
|
header: "お部屋の用意ができました!"
|
||||||
|
message: "{title} を作りました。参加者に以下の URL を共有してください。"
|
||||||
|
errors:
|
||||||
|
notFound: "{value} が見つかりません"
|
||||||
|
alreadyAdded: "すでに追加済みです"
|
||||||
|
connectionFailed: "接続できませんでした。"
|
||||||
|
alreadyConnected: "他のデバイスで入室済みです。切断された場合はしばらく待ってからやり直してください。"
|
||||||
|
alreadyClosed: "この部屋はすでに閉じられています。"
|
||||||
|
restriction:
|
||||||
|
following: "この部屋はホストのフォロー限定です。"
|
||||||
|
follower: "この部屋はホストのフォロワー限定です。"
|
||||||
|
knowing: "この部屋はホストのフォローまたはフォロワー限定です。"
|
||||||
|
mutual: "この部屋はホストの相互フォロー限定です。"
|
||||||
|
private: "この部屋は共同ホスト限定です。"
|
||||||
|
default: "入室が許可されていません。"
|
||||||
|
startListening: "視聴を始める"
|
||||||
|
browserMuted: "ブラウザの設定により無音になっています。続行するには @:startListening ボタンを押してください。"
|
||||||
|
speakRequest:
|
||||||
|
label: "発言リクエスト"
|
||||||
|
dialog: "発言をリクエストしますか?"
|
||||||
|
norequest: "リクエストはありません"
|
||||||
|
sent: "発言リクエストを送信しました"
|
||||||
|
receive: "新しい発言リクエストがあります"
|
||||||
|
microphoneBlocked: "ブラウザが録音を許可していません。"
|
||||||
|
closeRoomConfirm: "この部屋を閉じますか?"
|
||||||
|
roomEvent:
|
||||||
|
closedByHost: "ホストにより部屋が閉じられました。"
|
||||||
|
removed: "部屋から退去しました。"
|
|
@ -4,7 +4,11 @@ import { createPinia } from "pinia";
|
||||||
import { createVuetify } from "vuetify";
|
import { createVuetify } from "vuetify";
|
||||||
import { aliases, mdi } from "vuetify/iconsets/mdi-svg";
|
import { aliases, mdi } from "vuetify/iconsets/mdi-svg";
|
||||||
|
|
||||||
|
import { createI18n } from "vue-i18n";
|
||||||
|
import messages from "@intlify/unplugin-vue-i18n/messages";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { split } from "lodash-es";
|
||||||
|
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import router from "./router";
|
import router from "./router";
|
||||||
|
@ -27,6 +31,18 @@ const vuetify = createVuetify({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const userLocale =
|
||||||
|
navigator.languages && navigator.languages.length
|
||||||
|
? navigator.languages[0]
|
||||||
|
: navigator.language;
|
||||||
|
const prefLocale = localStorage.getItem("locale");
|
||||||
|
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: prefLocale ?? split(userLocale, "-", 1)[0],
|
||||||
|
fallbackLocale: "en",
|
||||||
|
messages,
|
||||||
|
});
|
||||||
|
|
||||||
axios.defaults.withCredentials = true;
|
axios.defaults.withCredentials = true;
|
||||||
|
|
||||||
// if audon server returns 401, display the login form
|
// if audon server returns 401, display the login form
|
||||||
|
@ -52,7 +68,7 @@ router.beforeEach(async (to) => {
|
||||||
router.afterEach((to, from) => {
|
router.afterEach((to, from) => {
|
||||||
const donStore = useMastodonStore();
|
const donStore = useMastodonStore();
|
||||||
if (!to.meta.noauth && !donStore.authorized) {
|
if (!to.meta.noauth && !donStore.authorized) {
|
||||||
const query = to.name !== "home" ? {l: to.path} : {};
|
const query = to.name !== "home" ? { l: to.path } : {};
|
||||||
router.push({ name: "login", query }); // need to push in afterEach to get nonempty lastPath in LoginView.vue
|
router.push({ name: "login", query }); // need to push in afterEach to get nonempty lastPath in LoginView.vue
|
||||||
} else if (to.name === "login" && donStore.authorized) {
|
} else if (to.name === "login" && donStore.authorized) {
|
||||||
router.replace({ name: "home" });
|
router.replace({ name: "home" });
|
||||||
|
@ -61,6 +77,7 @@ router.afterEach((to, from) => {
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
|
app.use(i18n);
|
||||||
app.use(createPinia());
|
app.use(createPinia());
|
||||||
app.use(vuetify);
|
app.use(vuetify);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
|
|
@ -17,7 +17,7 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="about">
|
<div class="about">
|
||||||
準備中
|
Under construction
|
||||||
<div>
|
<div>
|
||||||
<RouterLink :to="{ name: 'home' }">Home</RouterLink>
|
<RouterLink :to="{ name: 'home' }">Home</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -45,12 +45,12 @@ export default {
|
||||||
cohosts: [],
|
cohosts: [],
|
||||||
relationship: "everyone",
|
relationship: "everyone",
|
||||||
relOptions: [
|
relOptions: [
|
||||||
{ title: "制限なし", value: "everyone" },
|
{ title: this.$t("form.relationships.everyone"), value: "everyone" },
|
||||||
{ title: "あなたのフォロー限定", value: "following" },
|
{ title: this.$t("form.relationships.following"), value: "following" },
|
||||||
{ title: "あなたのフォロワー限定", value: "follower" },
|
{ title: this.$t("form.relationships.follower"), value: "follower" },
|
||||||
{ title: "あなたのフォローまたはフォロワー限定", value: "knowing" },
|
{ title: this.$t("form.relationships.knowing"), value: "knowing" },
|
||||||
{ title: "あなたの相互フォロー限定", value: "mutual" },
|
{ title: this.$t("form.relationships.mutual"), value: "mutual" },
|
||||||
{ title: "共同ホスト限定", value: "private" },
|
{ title: this.$t("form.relationships.private"), value: "private" },
|
||||||
],
|
],
|
||||||
scheduledAt: null,
|
scheduledAt: null,
|
||||||
searchResult: null,
|
searchResult: null,
|
||||||
|
@ -69,12 +69,12 @@ export default {
|
||||||
validations() {
|
validations() {
|
||||||
return {
|
return {
|
||||||
title: {
|
title: {
|
||||||
required: helpers.withMessage("部屋の名前を入力してください", required),
|
required: helpers.withMessage(this.$t("form.titleRequired"), required),
|
||||||
maxLength: maxLength(100)
|
maxLength: maxLength(100),
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
maxLength: maxLength(500)
|
maxLength: maxLength(500),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -95,9 +95,7 @@ export default {
|
||||||
if (!donURL) return "";
|
if (!donURL) return "";
|
||||||
const url = new URL(donURL);
|
const url = new URL(donURL);
|
||||||
const texts = [
|
const texts = [
|
||||||
"Audon で部屋を作りました!",
|
this.$t("shareRoomMessage", { link: this.roomURL, title: this.title }),
|
||||||
`参加用リンク: ${this.roomURL}`,
|
|
||||||
`タイトル: ${this.title}`,
|
|
||||||
];
|
];
|
||||||
if (this.description)
|
if (this.description)
|
||||||
texts.push(truncate("\n" + this.description, { length: 200 }));
|
texts.push(truncate("\n" + this.description, { length: 200 }));
|
||||||
|
@ -110,7 +108,7 @@ export default {
|
||||||
this.cohostSearch.cancel();
|
this.cohostSearch.cancel();
|
||||||
if (!val) return;
|
if (!val) return;
|
||||||
if (some(this.cohosts, { finger: val })) {
|
if (some(this.cohosts, { finger: val })) {
|
||||||
this.searchError.message = "すでに追加済みです";
|
this.searchError.message = this.$t("errors.alreadyAdded");
|
||||||
this.searchError.colour = "warning";
|
this.searchError.colour = "warning";
|
||||||
this.searchError.enabled = true;
|
this.searchError.enabled = true;
|
||||||
return;
|
return;
|
||||||
|
@ -141,7 +139,7 @@ export default {
|
||||||
this.searchResult = user;
|
this.searchResult = user;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.isMastoError && error.statusCode === 404) {
|
if (error.isMastoError && error.statusCode === 404) {
|
||||||
this.searchError.message = `${val} が見つかりません`;
|
this.searchError.message = this.$t("errors.notFound", { value: val });
|
||||||
this.searchError.colour = "error";
|
this.searchError.colour = "error";
|
||||||
this.searchError.enabled = true;
|
this.searchError.enabled = true;
|
||||||
}
|
}
|
||||||
|
@ -172,7 +170,7 @@ export default {
|
||||||
remote_id: u.id,
|
remote_id: u.id,
|
||||||
remote_url: u.url,
|
remote_url: u.url,
|
||||||
})),
|
})),
|
||||||
restriction: this.relationship
|
restriction: this.relationship,
|
||||||
};
|
};
|
||||||
this.isSubmissionLoading = false;
|
this.isSubmissionLoading = false;
|
||||||
try {
|
try {
|
||||||
|
@ -195,16 +193,12 @@ export default {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-dialog v-model="isDialogActive" persistent max-width="700">
|
<v-dialog v-model="isDialogActive" persistent max-width="700">
|
||||||
<v-alert
|
<v-alert type="success" color="blue-gray" :title="$t('roomReady.header')">
|
||||||
type="success"
|
|
||||||
color="blue-gray"
|
|
||||||
title="お部屋の用意ができました!"
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
{{ title }} を作りました。参加者に以下の URL を共有してください。
|
{{ $t("roomReady.message", { title }) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<h3 style="word-break: break-all;">{{ roomURL }}</h3>
|
<h3 style="word-break: break-all">{{ roomURL }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<v-btn
|
<v-btn
|
||||||
|
@ -213,7 +207,7 @@ export default {
|
||||||
@click="onShareClick"
|
@click="onShareClick"
|
||||||
color="#563ACC"
|
color="#563ACC"
|
||||||
size="small"
|
size="small"
|
||||||
>シェア</v-btn
|
>{{ $t("share") }}</v-btn
|
||||||
>
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
@click="clipboard.copy(roomURL)"
|
@click="clipboard.copy(roomURL)"
|
||||||
|
@ -222,7 +216,7 @@ export default {
|
||||||
:prepend-icon="
|
:prepend-icon="
|
||||||
clipboard.copied.value ? mdiClipboardCheck : mdiClipboardEdit
|
clipboard.copied.value ? mdiClipboardCheck : mdiClipboardEdit
|
||||||
"
|
"
|
||||||
>{{ clipboard.copied.value ? "コピーしました" : "コピー" }}</v-btn
|
>{{ clipboard.copied.value ? $t("copied") : $t("copy") }}</v-btn
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center mt-10 mb-1">
|
<div class="text-center mt-10 mb-1">
|
||||||
|
@ -230,7 +224,7 @@ export default {
|
||||||
color="indigo"
|
color="indigo"
|
||||||
:to="{ name: 'room', params: { id: createdRoomID } }"
|
:to="{ name: 'room', params: { id: createdRoomID } }"
|
||||||
size="large"
|
size="large"
|
||||||
>入室</v-btn
|
>{{ $t("enterRoom") }}</v-btn
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
@ -239,7 +233,7 @@ export default {
|
||||||
<div>
|
<div>
|
||||||
<v-btn class="ma-2" variant="text" color="blue" :to="{ name: 'home' }">
|
<v-btn class="ma-2" variant="text" color="blue" :to="{ name: 'home' }">
|
||||||
<v-icon start :icon="mdiArrowLeft"></v-icon>
|
<v-icon start :icon="mdiArrowLeft"></v-icon>
|
||||||
戻る
|
{{ $t("back") }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-snackbar
|
<v-snackbar
|
||||||
v-model="searchError.enabled"
|
v-model="searchError.enabled"
|
||||||
|
@ -251,12 +245,14 @@ export default {
|
||||||
{{ searchError.message }}
|
{{ searchError.message }}
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
<v-card :loading="isSubmissionLoading">
|
<v-card :loading="isSubmissionLoading">
|
||||||
<v-card-title class="text-center">部屋を新規作成</v-card-title>
|
<v-card-title class="text-center">{{
|
||||||
|
$t("createNewRoom")
|
||||||
|
}}</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-form>
|
<v-form>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="title"
|
v-model="title"
|
||||||
label="タイトル"
|
:label="$t('form.title')"
|
||||||
:counter="100"
|
:counter="100"
|
||||||
:error-messages="titleErrors"
|
:error-messages="titleErrors"
|
||||||
required
|
required
|
||||||
|
@ -267,18 +263,23 @@ export default {
|
||||||
auto-grow
|
auto-grow
|
||||||
v-model="description"
|
v-model="description"
|
||||||
rows="2"
|
rows="2"
|
||||||
label="説明"
|
:label="$t('form.description')"
|
||||||
:counter="500"
|
:counter="500"
|
||||||
></v-textarea>
|
></v-textarea>
|
||||||
<v-select
|
<v-select
|
||||||
:items="relOptions"
|
:items="relOptions"
|
||||||
label="入室制限"
|
:label="$t('form.restriction')"
|
||||||
v-model="relationship"
|
v-model="relationship"
|
||||||
:messages="['共同ホストは制限に関わらず入室できます']"
|
:messages="[$t('form.cohostCanAlwaysJoin')]"
|
||||||
></v-select>
|
></v-select>
|
||||||
<v-card class="my-3" variant="outlined">
|
<v-card class="my-3" variant="outlined">
|
||||||
<v-card-title class="text-subtitle-1">共同ホスト</v-card-title>
|
<v-card-title class="text-subtitle-1">{{
|
||||||
<v-card-text v-if="cohosts.length > 0 || searchResult" class="py-0">
|
$t("form.cohosts")
|
||||||
|
}}</v-card-title>
|
||||||
|
<v-card-text
|
||||||
|
v-if="cohosts.length > 0 || searchResult"
|
||||||
|
class="py-0"
|
||||||
|
>
|
||||||
<template v-if="cohosts.length > 0">
|
<template v-if="cohosts.length > 0">
|
||||||
<v-list lines="two" variant="tonal">
|
<v-list lines="two" variant="tonal">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
|
@ -358,15 +359,15 @@ export default {
|
||||||
<v-text-field
|
<v-text-field
|
||||||
type="datetime-local"
|
type="datetime-local"
|
||||||
v-model="scheduledAt"
|
v-model="scheduledAt"
|
||||||
label="開始予約"
|
:label="$t('form.schedule')"
|
||||||
disabled
|
disabled
|
||||||
:messages="['今後のアップデートで追加予定']"
|
:messages="[$t('comingFuture')]"
|
||||||
></v-text-field>
|
></v-text-field>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-btn block color="indigo" @click="onSubmit" variant="flat">
|
<v-btn block color="indigo" @click="onSubmit" variant="flat">
|
||||||
作成
|
{{ $t("create") }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
|
@ -15,7 +15,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async onLogout() {
|
async onLogout() {
|
||||||
if (!confirm("Audon からログアウトしますか?")) return;
|
// if (!confirm(this.$t("logoutConfirm"))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await axios.post("/app/logout");
|
const resp = await axios.post("/app/logout");
|
||||||
|
@ -42,7 +42,7 @@ export default {
|
||||||
color="red"
|
color="red"
|
||||||
@click="onLogout"
|
@click="onLogout"
|
||||||
>
|
>
|
||||||
ログアウト
|
{{ $t("logout") }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center my-10">
|
<div class="text-center my-10">
|
||||||
|
@ -65,7 +65,7 @@ export default {
|
||||||
<v-text-field v-mode="query"></v-text-field>
|
<v-text-field v-mode="query"></v-text-field>
|
||||||
</v-col> -->
|
</v-col> -->
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-btn block :to="{ name: 'create' }" color="indigo">部屋を作成</v-btn>
|
<v-btn block :to="{ name: 'create' }" color="indigo">{{ $t("createNewRoom") }}</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -21,9 +21,9 @@ export default {
|
||||||
validations() {
|
validations() {
|
||||||
return {
|
return {
|
||||||
server: {
|
server: {
|
||||||
required: helpers.withMessage("アドレスを入力してください", required),
|
required: helpers.withMessage(this.$t("addressRequired"), required),
|
||||||
hostname: helpers.withMessage(
|
hostname: helpers.withMessage(
|
||||||
"有効なアドレスを入力してください",
|
this.$t("invalidAddress"),
|
||||||
validators.fqdn
|
validators.fqdn
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
@ -56,7 +56,7 @@ export default {
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response?.status === 404) {
|
if (error.response?.status === 404) {
|
||||||
this.serverErr = "サーバーが見つかりません";
|
this.serverErr = this.$t("serverNotFound");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,14 +69,14 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-alert v-if="$route.query.warn" type="warning" variant="text">
|
<v-alert v-if="$route.query.l" type="warning" variant="text">
|
||||||
<div>ログインが必要です</div>
|
<div>{{ $t("loginRequired") }}</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
<v-form ref="form" @submit.prevent="onSubmit" class="my-3" lazy-validation>
|
<v-form ref="form" @submit.prevent="onSubmit" class="my-3" lazy-validation>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="server"
|
v-model="server"
|
||||||
name="server"
|
name="server"
|
||||||
label="Mastodon サーバー"
|
:label="$t('server')"
|
||||||
placeholder="mastodon.example"
|
placeholder="mastodon.example"
|
||||||
class="mb-2"
|
class="mb-2"
|
||||||
:error-messages="serverErrors"
|
:error-messages="serverErrors"
|
||||||
|
@ -85,10 +85,10 @@ export default {
|
||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
<v-btn block @click="onSubmit" :disabled="!v$.$dirty || v$.$error"
|
<v-btn block @click="onSubmit" :disabled="!v$.$dirty || v$.$error"
|
||||||
>ログイン</v-btn
|
>{{ $t("login") }}</v-btn
|
||||||
>
|
>
|
||||||
</v-form>
|
</v-form>
|
||||||
<div class="w-100 text-right">
|
<div class="w-100 text-right">
|
||||||
<RouterLink to="/about">利用規約</RouterLink>
|
<RouterLink to="/about">{{ $t("about") }}</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default {
|
||||||
editingRoomInfo: {
|
editingRoomInfo: {
|
||||||
title: {
|
title: {
|
||||||
required: helpers.withMessage(
|
required: helpers.withMessage(
|
||||||
"部屋の名前を入力してください",
|
this.$t("form.titleRequired"),
|
||||||
required
|
required
|
||||||
),
|
),
|
||||||
maxLength: maxLength(100),
|
maxLength: maxLength(100),
|
||||||
|
@ -102,12 +102,12 @@ export default {
|
||||||
restriction: "",
|
restriction: "",
|
||||||
},
|
},
|
||||||
relOptions: [
|
relOptions: [
|
||||||
{ title: "制限なし", value: "everyone" },
|
{ title: this.$t("form.relationships.everyone"), value: "everyone" },
|
||||||
{ title: "あなたのフォロー限定", value: "following" },
|
{ title: this.$t("form.relationships.following"), value: "following" },
|
||||||
{ title: "あなたのフォロワー限定", value: "follower" },
|
{ title: this.$t("form.relationships.follower"), value: "follower" },
|
||||||
{ title: "あなたのフォローまたはフォロワー限定", value: "knowing" },
|
{ title: this.$t("form.relationships.knowing"), value: "knowing" },
|
||||||
{ title: "あなたの相互フォロー限定", value: "mutual" },
|
{ title: this.$t("form.relationships.mutual"), value: "mutual" },
|
||||||
{ title: "共同ホスト限定", value: "private" },
|
{ title: this.$t("form.relationships.private"), value: "private" },
|
||||||
],
|
],
|
||||||
participants: {},
|
participants: {},
|
||||||
cachedMastoData: {},
|
cachedMastoData: {},
|
||||||
|
@ -245,10 +245,10 @@ export default {
|
||||||
let message = "";
|
let message = "";
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case DisconnectReason.ROOM_DELETED:
|
case DisconnectReason.ROOM_DELETED:
|
||||||
message = "ホストにより部屋が閉じられました。";
|
message = self.$t("roomEvent.closedByHost");
|
||||||
break;
|
break;
|
||||||
case DisconnectReason.PARTICIPANT_REMOVED:
|
case DisconnectReason.PARTICIPANT_REMOVED:
|
||||||
message = "部屋から退去しました";
|
message = self.$t("roomEvent.removed");
|
||||||
break;
|
break;
|
||||||
case DisconnectReason.CLIENT_INITIATED:
|
case DisconnectReason.CLIENT_INITIATED:
|
||||||
break;
|
break;
|
||||||
|
@ -330,7 +330,7 @@ export default {
|
||||||
publishOpts
|
publishOpts
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
alert("ブラウザが録音を許可していません");
|
alert(this.$t("microphoneBlocked"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -339,23 +339,22 @@ export default {
|
||||||
let message = "";
|
let message = "";
|
||||||
switch (error.response?.data) {
|
switch (error.response?.data) {
|
||||||
case "following":
|
case "following":
|
||||||
message = "この部屋はホストのフォロー限定です。";
|
message = this.$t("errors.restriction.following");
|
||||||
break;
|
break;
|
||||||
case "follower":
|
case "follower":
|
||||||
message = "この部屋はホストのフォロワー限定です。";
|
message = this.$t("errors.restriction.follower");
|
||||||
break;
|
break;
|
||||||
case "knowing":
|
case "knowing":
|
||||||
message =
|
message = this.$t("errors.restriction.knowing");
|
||||||
"この部屋はホストのフォローまたはフォロワー限定です。";
|
|
||||||
break;
|
break;
|
||||||
case "mutual":
|
case "mutual":
|
||||||
message = "この部屋はホストの相互フォロー限定です。";
|
message = this.$t("errors.restriction.mutual");
|
||||||
break;
|
break;
|
||||||
case "private":
|
case "private":
|
||||||
message = "この部屋は共同ホスト限定です。";
|
message = this.$t("errors.restriction.private");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
message = "入室が許可されていません。";
|
message = this.$t("errors.restriction.default");
|
||||||
}
|
}
|
||||||
alert(message);
|
alert(message);
|
||||||
break;
|
break;
|
||||||
|
@ -363,12 +362,10 @@ export default {
|
||||||
pushNotFound(this.$route);
|
pushNotFound(this.$route);
|
||||||
break;
|
break;
|
||||||
case 406:
|
case 406:
|
||||||
alert(
|
alert(this.$t("errors.alreadyConnected"));
|
||||||
"他のデバイスで入室済みです。切断された場合はしばらく待ってからやり直してください。"
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case 410:
|
case 410:
|
||||||
alert("この部屋はすでに閉じられています。");
|
alert(this.$t("errors.alreadyClosed"));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
alert(error);
|
alert(error);
|
||||||
|
@ -381,7 +378,7 @@ export default {
|
||||||
onResize() {
|
onResize() {
|
||||||
const mainArea = document.getElementById("mainArea");
|
const mainArea = document.getElementById("mainArea");
|
||||||
const height = mainArea.clientHeight;
|
const height = mainArea.clientHeight;
|
||||||
this.mainHeight = height > 700 ? 700 : window.innerHeight - 70;
|
this.mainHeight = height > 700 ? 700 : window.innerHeight - 95;
|
||||||
},
|
},
|
||||||
isHost(identity) {
|
isHost(identity) {
|
||||||
return identity === this.roomInfo.host?.audon_id;
|
return identity === this.roomInfo.host?.audon_id;
|
||||||
|
@ -427,7 +424,7 @@ export default {
|
||||||
await this.publishDataToHostAndCohosts(data);
|
await this.publishDataToHostAndCohosts(data);
|
||||||
},
|
},
|
||||||
async requestSpeak() {
|
async requestSpeak() {
|
||||||
if (confirm("発言をリクエストしますか?")) {
|
if (confirm(this.$t("speakRequest.dialog"))) {
|
||||||
await this.publishDataToHostAndCohosts({ kind: "speak_request" });
|
await this.publishDataToHostAndCohosts({ kind: "speak_request" });
|
||||||
this.showRequestedNotification = true;
|
this.showRequestedNotification = true;
|
||||||
}
|
}
|
||||||
|
@ -499,16 +496,15 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
alert("ブラウザが録音を許可していません");
|
alert(this.$t("microphoneBlocked"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// alert("リクエストはアップデートで実装予定です!");
|
|
||||||
this.requestSpeak();
|
this.requestSpeak();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onRoomClose() {
|
async onRoomClose() {
|
||||||
// TODO: change this from confirm to a vuetify thing
|
// TODO: change this from confirm to a vuetify thing
|
||||||
if (confirm("この部屋を閉じますか?")) {
|
if (confirm(this.$t("closeRoomConfirm"))) {
|
||||||
try {
|
try {
|
||||||
await axios.delete(`/api/room/${this.roomID}`);
|
await axios.delete(`/api/room/${this.roomID}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -521,7 +517,7 @@ export default {
|
||||||
await this.roomClient.startAudio();
|
await this.roomClient.startAudio();
|
||||||
this.autoplayDisabled = false;
|
this.autoplayDisabled = false;
|
||||||
} catch {
|
} catch {
|
||||||
alert("接続できませんでした。退室します。");
|
alert(this.$t("errors.connectionFailed"));
|
||||||
await this.roomClient.disconnect();
|
await this.roomClient.disconnect();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -557,11 +553,11 @@ export default {
|
||||||
<template>
|
<template>
|
||||||
<v-dialog v-model="showEditDialog" max-width="500" persistent>
|
<v-dialog v-model="showEditDialog" max-width="500" persistent>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>部屋の編集</v-card-title>
|
<v-card-title>{{ $t("editRoom") }}</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="editingRoomInfo.title"
|
v-model="editingRoomInfo.title"
|
||||||
label="タイトル"
|
:label="$t('form.title')"
|
||||||
:error-messages="titleErrors"
|
:error-messages="titleErrors"
|
||||||
:counter="100"
|
:counter="100"
|
||||||
required
|
required
|
||||||
|
@ -572,14 +568,14 @@ export default {
|
||||||
auto-grow
|
auto-grow
|
||||||
v-model="editingRoomInfo.description"
|
v-model="editingRoomInfo.description"
|
||||||
rows="2"
|
rows="2"
|
||||||
label="説明"
|
:label="$t('form.description')"
|
||||||
:counter="500"
|
:counter="500"
|
||||||
></v-textarea>
|
></v-textarea>
|
||||||
<v-select
|
<v-select
|
||||||
:items="relOptions"
|
:items="relOptions"
|
||||||
label="入室制限"
|
:label="$t('form.restriction')"
|
||||||
v-model="editingRoomInfo.restriction"
|
v-model="editingRoomInfo.restriction"
|
||||||
:messages="['共同ホストは制限に関わらず入室できます']"
|
:messages="[$t('form.cohostCanAlwaysJoin')]"
|
||||||
></v-select>
|
></v-select>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
|
@ -589,28 +585,32 @@ export default {
|
||||||
showEditDialog = false;
|
showEditDialog = false;
|
||||||
editingRoomInfo = clone(roomInfo);
|
editingRoomInfo = clone(roomInfo);
|
||||||
"
|
"
|
||||||
>キャンセル</v-btn
|
>{{ $t("cancel") }}</v-btn
|
||||||
>
|
>
|
||||||
<v-btn @click="onEditSubmit">保存</v-btn>
|
<v-btn @click="onEditSubmit">{{ $t("save") }}</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
<v-dialog v-model="autoplayDisabled" max-width="500" persistent>
|
<v-dialog v-model="autoplayDisabled" max-width="500" persistent>
|
||||||
<v-alert color="indigo">
|
<v-alert color="indigo">
|
||||||
<div class="mb-5">
|
<div class="mb-5">
|
||||||
ブラウザの設定により無音になっています。続行するには「視聴を始める」ボタンを押してください。
|
{{ $t("browserMuted") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center mb-3">
|
<div class="text-center mb-3">
|
||||||
<v-btn color="gray" @click="onStartListening">視聴を始める</v-btn>
|
<v-btn color="gray" @click="onStartListening">{{
|
||||||
|
$t("startListening")
|
||||||
|
}}</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<v-btn variant="text" @click="roomClient.disconnect()">退室する</v-btn>
|
<v-btn variant="text" @click="roomClient.disconnect()">{{
|
||||||
|
$t("leaveRoom")
|
||||||
|
}}</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
<v-dialog v-model="showRequestDialog" max-width="500">
|
<v-dialog v-model="showRequestDialog" max-width="500">
|
||||||
<v-card max-height="600" class="d-flex flex-column">
|
<v-card max-height="600" class="d-flex flex-column">
|
||||||
<v-card-title>発言リクエスト</v-card-title>
|
<v-card-title>{{ $t("speakRequest.label") }}</v-card-title>
|
||||||
<v-card-text class="flex-grow-1 overflow-auto py-0">
|
<v-card-text class="flex-grow-1 overflow-auto py-0">
|
||||||
<v-list v-if="speakRequests.size > 0" lines="two" variant="tonal">
|
<v-list v-if="speakRequests.size > 0" lines="two" variant="tonal">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
|
@ -651,11 +651,13 @@ export default {
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
<p class="text-center py-3" v-else>リクエストはありません</p>
|
<p class="text-center py-3" v-else>
|
||||||
|
{{ $t("speakRequest.norequest") }}
|
||||||
|
</p>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-divider></v-divider>
|
<v-divider></v-divider>
|
||||||
<v-card-actions class="justify-end">
|
<v-card-actions class="justify-end">
|
||||||
<v-btn @click="showRequestDialog = false">閉じる</v-btn>
|
<v-btn @click="showRequestDialog = false">{{ $t("close") }}</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
@ -665,7 +667,7 @@ export default {
|
||||||
v-model="showRequestedNotification"
|
v-model="showRequestedNotification"
|
||||||
color="info"
|
color="info"
|
||||||
>
|
>
|
||||||
<strong>発言リクエストを送信しました!</strong>
|
<strong>{{ $t("speakRequest.sent") }}</strong>
|
||||||
<template v-slot:actions>
|
<template v-slot:actions>
|
||||||
<v-btn
|
<v-btn
|
||||||
variant="text"
|
variant="text"
|
||||||
|
@ -688,7 +690,7 @@ export default {
|
||||||
showRequestNotification = false;
|
showRequestNotification = false;
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<strong>新しい発言リクエストがあります</strong>
|
<strong>{{ $t("speakRequest.receive") }}</strong>
|
||||||
</div>
|
</div>
|
||||||
<template v-slot:actions>
|
<template v-slot:actions>
|
||||||
<v-btn
|
<v-btn
|
||||||
|
@ -717,12 +719,12 @@ export default {
|
||||||
</template>
|
</template>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
title="編集"
|
:title="$t('edit')"
|
||||||
:prepend-icon="mdiPencil"
|
:prepend-icon="mdiPencil"
|
||||||
@click="showEditDialog = true"
|
@click="showEditDialog = true"
|
||||||
></v-list-item>
|
></v-list-item>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
title="閉室"
|
:title="$t('closeRoom')"
|
||||||
:prepend-icon="mdiDoorClosed"
|
:prepend-icon="mdiDoorClosed"
|
||||||
@click="onRoomClose"
|
@click="onRoomClose"
|
||||||
></v-list-item>
|
></v-list-item>
|
||||||
|
|
|
@ -4,9 +4,17 @@ import { defineConfig } from "vite";
|
||||||
import vue from "@vitejs/plugin-vue";
|
import vue from "@vitejs/plugin-vue";
|
||||||
import vuetify from "vite-plugin-vuetify";
|
import vuetify from "vite-plugin-vuetify";
|
||||||
|
|
||||||
|
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [vue(), vuetify({ autoImport: true })],
|
plugins: [
|
||||||
|
vue(),
|
||||||
|
vuetify({ autoImport: true }),
|
||||||
|
VueI18nPlugin({
|
||||||
|
include: "./src/locales/*.yaml",
|
||||||
|
}),
|
||||||
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||||
|
|
|
@ -44,7 +44,7 @@ services:
|
||||||
|
|
||||||
audon:
|
audon:
|
||||||
build: .
|
build: .
|
||||||
image: namekuji/audon
|
image: nmkj/audon
|
||||||
env_file:
|
env_file:
|
||||||
- .env.production
|
- .env.production
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
2
room.go
2
room.go
|
@ -194,7 +194,7 @@ func joinRoomHandler(c echo.Context) (err error) {
|
||||||
|
|
||||||
// check room restriction
|
// check room restriction
|
||||||
if room.IsPrivate() && !canTalk {
|
if room.IsPrivate() && !canTalk {
|
||||||
return ErrOperationNotPermitted
|
return c.String(http.StatusForbidden, string(room.Restriction))
|
||||||
}
|
}
|
||||||
if !canTalk && (room.IsFollowingOnly() || room.IsFollowerOnly() || room.IsFollowingOrFollowerOnly() || room.IsMutualOnly()) {
|
if !canTalk && (room.IsFollowingOnly() || room.IsFollowerOnly() || room.IsFollowingOrFollowerOnly() || room.IsMutualOnly()) {
|
||||||
mastoClient, _ := getMastodonClient(c)
|
mastoClient, _ := getMastodonClient(c)
|
||||||
|
|
Ładowanie…
Reference in New Issue