Merge branch 'develop' into perf/10923

This commit is contained in:
Acid Chicken (硫酸鶏) 2023-05-31 22:49:03 +09:00 committed by GitHub
commit 4af72b1c4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 753 additions and 655 deletions

View file

@ -32,11 +32,13 @@
- ハッシュタグのノート一覧ページから、そのハッシュタグで投稿するボタンを追加 - ハッシュタグのノート一覧ページから、そのハッシュタグで投稿するボタンを追加
- アカウント初期設定ウィザードに戻るボタンを追加 - アカウント初期設定ウィザードに戻るボタンを追加
- アカウントの初期設定ウィザードにあとでボタンを追加 - アカウントの初期設定ウィザードにあとでボタンを追加
- サーバーにカスタム絵文字の種類が多い場合のパフォーマンスの改善
- Fix: URLプレビューで情報が取得できなかった際の挙動を修正 - Fix: URLプレビューで情報が取得できなかった際の挙動を修正
- Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正 - Fix: Safari、Firefoxでの新規登録時、パスワードマネージャーにメールアドレスが登録されていた挙動を修正
- Fix: ロールタイムラインが無効でも投稿が流れてしまう問題の修正 - Fix: ロールタイムラインが無効でも投稿が流れてしまう問題の修正
- Fix: ロールタイムラインにて全ての投稿が流れてしまう問題の修正 - Fix: ロールタイムラインにて全ての投稿が流れてしまう問題の修正
- Fix: 「アクセストークンの管理」画面でアプリの情報が表示されない問題の修正 - Fix: 「アクセストークンの管理」画面でアプリの情報が表示されない問題の修正
- Fix: Firefoxにおける絵文字ピッカーのTabキーフォーカス問題の修正
### Server ### Server
- bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善 - bullをbull-mqにアップグレードし、ジョブキューのパフォーマンスを改善
@ -366,6 +368,7 @@ Meilisearchの設定に`index`が必要になりました。値はMisskeyサー
- アンテナでCWも検索対象にするように - アンテナでCWも検索対象にするように
- ノートの操作部をホバー時のみ表示するオプションを追加 - ノートの操作部をホバー時のみ表示するオプションを追加
- サウンドを追加 - サウンドを追加
- enhance(client): MFMのx2, scale, positionが含まれていたらートをたたむように
- サーバーのパフォーマンスを改善 - サーバーのパフォーマンスを改善
### Bugfixes ### Bugfixes

View file

@ -47,11 +47,13 @@ copyContent: "内容をコピー"
copyLink: "リンクをコピー" copyLink: "リンクをコピー"
delete: "ほかす" delete: "ほかす"
deleteAndEdit: "ほかして直す" deleteAndEdit: "ほかして直す"
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Renote、返信も全部消えるんやけどそれでもええん" deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、Renote、返信も全部消えるんやけどそれでもええん"
addToList: "リストに入れたる" addToList: "リストに入れたる"
sendMessage: "メッセージを送る" sendMessage: "メッセージを送る"
copyRSS: "RSSをコピー" copyRSS: "RSSをコピー"
copyUsername: "ユーザー名をコピー" copyUsername: "ユーザー名をコピー"
copyUserId: "ユーザーIDをコピー"
copyNoteId: "ートIDをコピー"
searchUser: "ユーザーを検索" searchUser: "ユーザーを検索"
reply: "返事" reply: "返事"
loadMore: "まだまだあるで!" loadMore: "まだまだあるで!"
@ -1043,6 +1045,10 @@ preventAiLearning: "生成AIの学習に使わんといて"
preventAiLearningDescription: "他の文章生成AIとか画像生成AIに、投稿したートとか画像なんかを勝手に使わんように頼むで。具体的にはnoaiフラグをHTMLレスポンスに含めるんやけど、これ聞いてくれるんはAIの気分次第やから、使われる可能性もちょっとはあるな。" preventAiLearningDescription: "他の文章生成AIとか画像生成AIに、投稿したートとか画像なんかを勝手に使わんように頼むで。具体的にはnoaiフラグをHTMLレスポンスに含めるんやけど、これ聞いてくれるんはAIの気分次第やから、使われる可能性もちょっとはあるな。"
options: "オプション" options: "オプション"
specifyUser: "ユーザー指定" specifyUser: "ユーザー指定"
rolesThatCanBeUsedThisEmojiAsReaction: "ツッコミとして使えるロール"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ロールが一個も指定されてへんかったら、誰でもツッコミとして使えるで。"
cancelReactionConfirm: "ツッコむんをやっぱやめるか?"
changeReactionConfirm: "ツッコミを別のに変えるか?"
_initialAccountSetting: _initialAccountSetting:
accountCreated: "アカウント作り終わったで。" accountCreated: "アカウント作り終わったで。"
letsStartAccountSetup: "アカウントの初期設定をしよか。" letsStartAccountSetup: "アカウントの初期設定をしよか。"
@ -1614,7 +1620,7 @@ _timelineTutorial:
step2_2: "最初のノートは、自己紹介とか「{name}始めてみたんや」とかがええと思うで。" step2_2: "最初のノートは、自己紹介とか「{name}始めてみたんや」とかがええと思うで。"
step3_1: "投稿できた?" step3_1: "投稿できた?"
step3_2: "あんたのノートがタイムラインに出てきたら成功や。" step3_2: "あんたのノートがタイムラインに出てきたら成功や。"
step4_1: "ノートには、「リアクション」を付けれるで。" step4_1: "ノートには、「ツッコミ」を付けれるで。"
step4_2: "ツッコむんやったら、ノートの「+」マークを押して、好きな絵文字を選ぶで。" step4_2: "ツッコむんやったら、ノートの「+」マークを押して、好きな絵文字を選ぶで。"
_2fa: _2fa:
alreadyRegistered: "もう設定終わっとるわ。" alreadyRegistered: "もう設定終わっとるわ。"

View file

@ -52,6 +52,8 @@ addToList: "리스트에 추가"
sendMessage: "메시지 보내기" sendMessage: "메시지 보내기"
copyRSS: "RSS 복사" copyRSS: "RSS 복사"
copyUsername: "유저명 복사" copyUsername: "유저명 복사"
copyUserId: "유저 ID 복사"
copyNoteId: "노트 ID 복사"
searchUser: "사용자 검색" searchUser: "사용자 검색"
reply: "답글" reply: "답글"
loadMore: "더 보기" loadMore: "더 보기"
@ -505,7 +507,7 @@ objectStoragePrefixDesc: "이 Prefix 의 디렉토리 아래에 파일이 저장
objectStorageEndpoint: "Endpoint" objectStorageEndpoint: "Endpoint"
objectStorageEndpointDesc: "AWS S3의 경우 공란, 다른 서비스의 경우 각 서비스의 가이드에 맞게 endpoint를 설정해주세요. '<host>' 혹은 '<host>:<port>' 와 같이 지정합니다." objectStorageEndpointDesc: "AWS S3의 경우 공란, 다른 서비스의 경우 각 서비스의 가이드에 맞게 endpoint를 설정해주세요. '<host>' 혹은 '<host>:<port>' 와 같이 지정합니다."
objectStorageRegion: "Region" objectStorageRegion: "Region"
objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요." objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해 주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요."
objectStorageUseSSL: "SSL 사용" objectStorageUseSSL: "SSL 사용"
objectStorageUseSSLDesc: "API 호출시 HTTPS 를 사용하지 않는 경우 OFF 로 설정해 주세요" objectStorageUseSSLDesc: "API 호출시 HTTPS 를 사용하지 않는 경우 OFF 로 설정해 주세요"
objectStorageUseProxy: "연결에 프록시를 사용" objectStorageUseProxy: "연결에 프록시를 사용"
@ -790,6 +792,7 @@ noMaintainerInformationWarning: "관리자 정보가 설정되어 있지 않습
noBotProtectionWarning: "Bot 방어가 설정되어 있지 않습니다." noBotProtectionWarning: "Bot 방어가 설정되어 있지 않습니다."
configure: "설정하기" configure: "설정하기"
postToGallery: "갤러리에 업로드" postToGallery: "갤러리에 업로드"
postToHashtag: "이 해시태그에 게시"
gallery: "갤러리" gallery: "갤러리"
recentPosts: "최근 포스트" recentPosts: "최근 포스트"
popularPosts: "인기 포스트" popularPosts: "인기 포스트"
@ -823,6 +826,7 @@ translatedFrom: "{x}에서 번역"
accountDeletionInProgress: "계정 삭제 작업을 진행하고 있습니다" accountDeletionInProgress: "계정 삭제 작업을 진행하고 있습니다"
usernameInfo: "서버상에서 계정을 식별하기 위한 이름. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있습니다. 사용자명은 나중에 변경할 수 없습니다." usernameInfo: "서버상에서 계정을 식별하기 위한 이름. 알파벳(a~z, A~Z), 숫자(0~9) 및 언더바(_)를 사용할 수 있습니다. 사용자명은 나중에 변경할 수 없습니다."
aiChanMode: "아이 모드" aiChanMode: "아이 모드"
devMode: "개발자 모드"
keepCw: "CW 유지하기" keepCw: "CW 유지하기"
pubSub: "Pub/Sub 계정" pubSub: "Pub/Sub 계정"
lastCommunication: "마지막 통신" lastCommunication: "마지막 통신"
@ -830,8 +834,10 @@ resolved: "해결됨"
unresolved: "해결되지 않음" unresolved: "해결되지 않음"
breakFollow: "팔로워 해제" breakFollow: "팔로워 해제"
breakFollowConfirm: "팔로우를 해제하시겠습니까?" breakFollowConfirm: "팔로우를 해제하시겠습니까?"
itsOn: "켜짐" itsOn: "켜져 있습니다"
itsOff: "꺼짐" itsOff: "꺼져 있습니다"
on: "켜짐"
off: "꺼짐"
emailRequiredForSignup: "가입할 때 이메일 주소 입력을 필수로 하기" emailRequiredForSignup: "가입할 때 이메일 주소 입력을 필수로 하기"
unread: "읽지 않음" unread: "읽지 않음"
filter: "필터" filter: "필터"
@ -986,6 +992,8 @@ cannotBeChangedLater: "나중에 변경할 수 없습니다."
reactionAcceptance: "리액션 수신" reactionAcceptance: "리액션 수신"
likeOnly: "좋아요만 받기" likeOnly: "좋아요만 받기"
likeOnlyForRemote: "리모트에서는 좋아요만 받기" likeOnlyForRemote: "리모트에서는 좋아요만 받기"
nonSensitiveOnly: "열람 주의로 설정되지 않았을 때만 받기"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "열람 주의로 설정되지 않았을 때만 받기 (리모트에서는 좋아요만 받기)"
rolesAssignedToMe: "나에게 할당된 역할" rolesAssignedToMe: "나에게 할당된 역할"
resetPasswordConfirm: "비밀번호를 재설정하시겠습니까?" resetPasswordConfirm: "비밀번호를 재설정하시겠습니까?"
sensitiveWords: "민감한 단어" sensitiveWords: "민감한 단어"
@ -1043,20 +1051,30 @@ preventAiLearning: "기계학습(생성형 AI)으로의 사용을 거부"
preventAiLearningDescription: "외부의 문장 생성 AI나 이미지 생성 AI에 대해 제출한 노트나 이미지 등의 콘텐츠를 학습의 대상으로 사용하지 않도록 요구합니다. 다만, 이 요구사항을 지킬 의무는 없기 때문에 학습을 완전히 방지하는 것은 아닙니다." preventAiLearningDescription: "외부의 문장 생성 AI나 이미지 생성 AI에 대해 제출한 노트나 이미지 등의 콘텐츠를 학습의 대상으로 사용하지 않도록 요구합니다. 다만, 이 요구사항을 지킬 의무는 없기 때문에 학습을 완전히 방지하는 것은 아닙니다."
options: "옵션" options: "옵션"
specifyUser: "사용자 지정" specifyUser: "사용자 지정"
failedToPreviewUrl: "미리 볼 수 없음"
update: "업데이트"
rolesThatCanBeUsedThisEmojiAsReaction: "이 이모지를 리액션으로 사용할 수 있는 역할"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "역할을 지정하지 않으면, 누구나 이 이모지를 리액션으로 사용할 수 있습니다."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "역할은 공개로 설정되어 있어야 합니다."
cancelReactionConfirm: "리액션을 취소하시겠습니까?"
changeReactionConfirm: "리액션을 변경하시겠습니까?"
later: "나중에"
goToMisskey: "Misskey로"
_initialAccountSetting: _initialAccountSetting:
accountCreated: "계정 생성이 완료되었습니다!" accountCreated: "계정 생성이 완료되었습니다!"
letsStartAccountSetup: "계정의 초기 설정을 진행합니다." letsStartAccountSetup: "계정의 초기 설정을 진행합니다."
letsFillYourProfile: "우선 나의 프로필을 설정해 보아요." letsFillYourProfile: "우선 나의 프로필을 설정해 보아요."
profileSetting: "프로필 설정" profileSetting: "프로필 설정"
privacySetting: "\n프라이버시설정" privacySetting: "\n프라이버시 설정"
theseSettingsCanEditLater: "이 설정들은 나중에도 변경할 수 있습니다." theseSettingsCanEditLater: "이 설정들은 나중에도 변경할 수 있습니다."
youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 맛게 조절할 수 있습니다. 꼭 확인해 보세요!" youCanEditMoreSettingsInSettingsPageLater: "이 외에도 '설정' 페이지에서 다양한 설정을 나의 입맛에 게 조절할 수 있습니다. 꼭 확인해 보세요!"
followUsers: "관심사가 맞는 유저를 팔로우하여 타임라인을 가꾸어 봅시다." followUsers: "관심사가 맞는 유저를 팔로우하여 타임라인을 가꾸어 봅시다."
pushNotificationDescription: "푸시 알림을 활성화하면 {name}의 알림을 나의 기기에서 받아볼 수 있게 됩니다." pushNotificationDescription: "푸시 알림을 활성화하면 {name}의 알림을 나의 기기에서 받아볼 수 있게 됩니다."
initialAccountSettingCompleted: "초기 설정을 모두 마쳤습니다!" initialAccountSettingCompleted: "초기 설정을 모두 마쳤습니다!"
haveFun: "{name}와 함께 즐거운 시간 보내세요!" haveFun: "{name}와 함께 즐거운 시간 보내세요!"
ifYouNeedLearnMore: "{name}(Misskey)의 사용 방법에 대해 자세히 알아보려면 {link}를 참고해 주세요." ifYouNeedLearnMore: "{name}(Misskey)의 사용 방법에 대해 자세히 알아보려면 {link}를 참고해 주세요."
skipAreYouSure: "초기 설정을 넘기시겠습니까?" skipAreYouSure: "초기 설정을 넘기시겠습니까?"
laterAreYouSure: "초기 설정을 나중에 다시 진행하시겠습니까?"
_serverRules: _serverRules:
description: "회원 가입 이전에 간단하게 표시할 서버 규칙입니다. 이용 약관의 요약으로 구성하는 것을 추천합니다." description: "회원 가입 이전에 간단하게 표시할 서버 규칙입니다. 이용 약관의 요약으로 구성하는 것을 추천합니다."
_accountMigration: _accountMigration:

View file

@ -1,5 +1,7 @@
--- ---
_lang_: "Norsk Bokmål" _lang_: "Norsk Bokmål"
headlineMisskey: "Et nettverk forbundet med notes"
introMisskey: "Velkommen! Misskey er en desentralisert mikrobloggtjeneste med åpen kildekode.\nOpprett \"notes\" for å dele tankene dine med alle rundt deg. 📡\nMed \"reaksjoner\" kan du også raskt gi uttrykk for hva du synes om alles notes. 👍\nLa oss utforske en ny verden! 🚀"
monthAndDay: "{day}-{month}" monthAndDay: "{day}-{month}"
search: "Søk" search: "Søk"
notifications: "Varsler" notifications: "Varsler"
@ -10,8 +12,10 @@ fetchingAsApObject: "Henter fra Fediverse..."
ok: "OK" ok: "OK"
gotIt: "Skjønner" gotIt: "Skjønner"
cancel: "Avbryt" cancel: "Avbryt"
noThankYou: "Avbryt" noThankYou: "Ikke nå"
enterUsername: "Skriv inn brukernavn" enterUsername: "Skriv inn brukernavn"
renotedBy: "Renotes av {user}"
noNotes: "Ingen notes"
noNotifications: "Ingen varsler" noNotifications: "Ingen varsler"
instance: "Server" instance: "Server"
settings: "Innstillinger" settings: "Innstillinger"
@ -30,20 +34,21 @@ uploading: "Laster opp"
save: "Lagre" save: "Lagre"
users: "Brukere" users: "Brukere"
addUser: "Legg til bruker" addUser: "Legg til bruker"
favorite: "Favoritt" favorite: "Legg til i favoritter"
favorites: "Favoritter" favorites: "Favoritter"
unfavorite: "Fjern favoritt" unfavorite: "Fjern fra favoritter"
favorited: "Lagt til i favoritter." favorited: "Lagt til i favoritter."
alreadyFavorited: "Allerede lagt til i favoritter." alreadyFavorited: "Allerede lagt til i favoritter."
cantFavorite: "Kunne ikke legge til i favoritter." cantFavorite: "Kunne ikke legge til i favoritter."
pin: "Fest" pin: "Fest til profil"
unpin: "Opphev festing" unpin: "Fjern fra profil"
copyContent: "Kopier innhold" copyContent: "Kopier innhold"
copyLink: "Kopier lenke" copyLink: "Kopier lenke"
delete: "Slett" delete: "Slett"
deleteAndEdit: "Slett og rediger" deleteAndEdit: "Slett og rediger"
deleteAndEditConfirm: "Er du sikker på at du vil slette denne noten og redigere den? Du vil miste alle reaksjoner, renotes og svar på den."
addToList: "Legg til i liste" addToList: "Legg til i liste"
sendMessage: "Send melding" sendMessage: "Send en melding"
copyRSS: "Kopier RSS" copyRSS: "Kopier RSS"
copyUsername: "Kopier brukernavn" copyUsername: "Kopier brukernavn"
searchUser: "Søk brukere" searchUser: "Søk brukere"
@ -63,7 +68,9 @@ unfollowConfirm: "Er du sikker på at du vil slutte å følge {name}?"
importRequested: "Du har bedt om import. Dette kan ta en stund." importRequested: "Du har bedt om import. Dette kan ta en stund."
lists: "Lister" lists: "Lister"
noLists: "Ingen lister" noLists: "Ingen lister"
following: "Følg" note: "Note"
notes: "Notes"
following: "Følger"
followers: "Følgere" followers: "Følgere"
followsYou: "Følger deg" followsYou: "Følger deg"
createList: "Opprett liste" createList: "Opprett liste"
@ -80,8 +87,13 @@ followRequests: "Følgeforespørsel"
unfollow: "Avfølg" unfollow: "Avfølg"
followRequestPending: "Venter på godkjenning" followRequestPending: "Venter på godkjenning"
enterEmoji: "Skriv inn en emoji" enterEmoji: "Skriv inn en emoji"
renote: "Renote"
renoted: "Renotet."
cantRenote: "Dette innlegget kan ikke renotes."
cantReRenote: "En renote kan ikke renotes."
quote: "Sitat" quote: "Sitat"
pinned: "Fest" pinnedNote: "Festet note"
pinned: "Fest til profil"
you: "Du" you: "Du"
clickToShow: "Klikk for å vise" clickToShow: "Klikk for å vise"
add: "Legg til" add: "Legg til"
@ -89,18 +101,21 @@ reaction: "Reaksjon"
reactions: "Reaksjoner" reactions: "Reaksjoner"
reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren" reactionSetting: "Reaksjoner som vises i reaksjonsvelgeren"
reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til." reactionSettingDescription2: "Dra for å endre rekkefølgen, klikk for å slette, trykk \"+\" for å legge til."
rememberNoteVisibility: "Husk innstillingene for synlighet av notes"
attachCancel: "Fjern vedlegg" attachCancel: "Fjern vedlegg"
enterFileName: "Skriv inn filnavn" enterFileName: "Skriv inn filnavn"
mute: "Skjul" mute: "Skjul"
unmute: "Vis" unmute: "Vis"
renoteMute: "Skjul renotes"
renoteUnmute: "Vis renotes"
block: "Blokker" block: "Blokker"
unblock: "Opphev blokkering" unblock: "Opphev blokkering"
suspend: "Suspender" suspend: "Suspender"
blockConfirm: "Blokker?" blockConfirm: "Er du sikker på at du vil blokke denne kontoen?"
unblockConfirm: "Er du sikker på at du vil oppheve blokkeringen av denne kontoen?" unblockConfirm: "Er du sikker på at du vil oppheve blokkeringen av denne kontoen?"
suspendConfirm: "Er du sikker på at du vil suspendere denne kontoen?" suspendConfirm: "Er du sikker på at du vil suspendere denne kontoen?"
selectList: "Velg liste" selectList: "Velg en liste"
selectChannel: "Velg kanal" selectChannel: "Velg en kanal"
selectAntenna: "Velg en antenne" selectAntenna: "Velg en antenne"
selectWidget: "Velg en widget" selectWidget: "Velg en widget"
editWidgets: "Rediger widgeter" editWidgets: "Rediger widgeter"
@ -113,6 +128,7 @@ flagAsBot: "Merk denne kontoen som en bot"
flagAsBotDescription: "Aktiver dette alternativet hvis denne kontoen styres av et program. Hvis det er aktivert, vil det fungere som et flagg for andre utviklere for å forhindre endeløse interaksjonskjeder med andre roboter og justere Misskeys interne systemer til å behandle denne kontoen som en bot." flagAsBotDescription: "Aktiver dette alternativet hvis denne kontoen styres av et program. Hvis det er aktivert, vil det fungere som et flagg for andre utviklere for å forhindre endeløse interaksjonskjeder med andre roboter og justere Misskeys interne systemer til å behandle denne kontoen som en bot."
flagAsCat: "Merk denne kontoen som en katt" flagAsCat: "Merk denne kontoen som en katt"
flagAsCatDescription: "Aktiver dette alternativet for å merke denne kontoen som en katt." flagAsCatDescription: "Aktiver dette alternativet for å merke denne kontoen som en katt."
flagShowTimelineReplies: "Vis svar i tidslinje"
addAccount: "Legg til konto" addAccount: "Legg til konto"
reloadAccountsList: "Last inn kontoliste på nytt" reloadAccountsList: "Last inn kontoliste på nytt"
loginFailed: "Kunne ikke logge inn" loginFailed: "Kunne ikke logge inn"
@ -120,12 +136,15 @@ general: "Generelt"
searchWith: "Søk: {q}" searchWith: "Søk: {q}"
youHaveNoLists: "Du har ingen lister" youHaveNoLists: "Du har ingen lister"
followConfirm: "Er du sikker på at du vil følge {name}?" followConfirm: "Er du sikker på at du vil følge {name}?"
selectUser: "Velg bruker" host: "Vert"
selectUser: "Velg en bruker"
recipient: "Mottaker" recipient: "Mottaker"
annotation: "Kommentarer" annotation: "Kommentarer"
federation: "Føderasjon" federation: "Føderasjon"
instances: "Server" instances: "Servere"
registeredAt: "Registrerte seg" registeredAt: "Registrerte seg"
latestRequestReceivedAt: "Siste forespørsel mottatt"
latestStatus: "Siste status"
perHour: "Per time" perHour: "Per time"
perDay: "Per dag" perDay: "Per dag"
stopActivityDelivery: "Slutt å sende aktiviteter" stopActivityDelivery: "Slutt å sende aktiviteter"
@ -136,7 +155,7 @@ withNFiles: "{n} fil(er)"
network: "Nettverk" network: "Nettverk"
statistics: "Statistikk" statistics: "Statistikk"
clearQueue: "Tøm kø" clearQueue: "Tøm kø"
clearQueueConfirmTitle: "Vil du tømme kø?" clearQueueConfirmTitle: "Er du sikker på at du vil tømme køen?"
blockedInstances: "Blokkerte severe" blockedInstances: "Blokkerte severe"
blockedInstancesDescription: "Skriv opp vertsnavnene til serverne du vil blokkere, atskilt med linjeskift. Serverne i listen vil ikke lenger kunne kommunisere med denne serveren." blockedInstancesDescription: "Skriv opp vertsnavnene til serverne du vil blokkere, atskilt med linjeskift. Serverne i listen vil ikke lenger kunne kommunisere med denne serveren."
muteAndBlock: "Skjul og blokker" muteAndBlock: "Skjul og blokker"
@ -144,9 +163,11 @@ mutedUsers: "Skjulte brukere"
blockedUsers: "Blokkerte brukere" blockedUsers: "Blokkerte brukere"
noUsers: "Det er ingen brukere" noUsers: "Det er ingen brukere"
editProfile: "Rediger profil" editProfile: "Rediger profil"
noteDeleteConfirm: "Er du sikker på at du vil slette denne noten?"
pinLimitExceeded: "Du kan ikke feste flere." pinLimitExceeded: "Du kan ikke feste flere."
intro: "Installasjonen av Misskey er ferdig! Vennligst opprett en administratorkonto."
done: "Ferdig" done: "Ferdig"
noCustomEmojis: "Ingen emoji" noCustomEmojis: "Det er ingen emoji"
noJobs: "Det er ingen jobber" noJobs: "Det er ingen jobber"
blocked: "Blokkert" blocked: "Blokkert"
suspended: "Suspendert" suspended: "Suspendert"
@ -160,11 +181,13 @@ attachFile: "Legg ved filer"
more: "Mer!" more: "Mer!"
announcements: "Kunngjøringer" announcements: "Kunngjøringer"
remove: "Slett" remove: "Slett"
removed: "Slettet" removed: "Vellykket slettet"
removeAreYouSure: "Er du sikker på at du vil fjerne \"{x}\"?" removeAreYouSure: "Er du sikker på at du vil fjerne \"{x}\"?"
deleteAreYouSure: "Er du sikker på at du vil slette \"{x}\"?" deleteAreYouSure: "Er du sikker på at du vil slette \"{x}\"?"
saved: "Lagret" saved: "Lagret"
upload: "Laste opp" upload: "Laste opp"
keepOriginalUploading: "Behold originalbildet"
fromUrl: "Fra URL"
explore: "Utforsk" explore: "Utforsk"
messageRead: "Lest" messageRead: "Lest"
agree: "Jeg godtar" agree: "Jeg godtar"
@ -178,16 +201,16 @@ yearsOld: "{age} år gammel"
light: "Lys" light: "Lys"
dark: "Mørk" dark: "Mørk"
fileName: "Filnavn" fileName: "Filnavn"
selectFile: "Velg fil" selectFile: "Velg en fil"
selectFiles: "Velg fil" selectFiles: "Velg filer"
selectFolder: "Velg mappe" selectFolder: "Velg en mappe"
selectFolders: "Velg mappe" selectFolders: "Velg mapper"
renameFile: "Endre filnavn" renameFile: "Endre filnavn"
folderName: "Mappenavn" folderName: "Mappenavn"
createFolder: "Opprett mappe" createFolder: "Opprett en mappe"
renameFolder: "Endre mappenavn" renameFolder: "Endre mappenavn"
deleteFolder: "Slett mappe" deleteFolder: "Slett denne mappen"
addFile: "Legg til fil" addFile: "Legg til en fil"
emptyFolder: "Denne mappen er tom" emptyFolder: "Denne mappen er tom"
unableToDelete: "Kan ikke slette" unableToDelete: "Kan ikke slette"
circularReferenceFolder: "Målmappen er en undermappe til mappen du ønsker å flytte." circularReferenceFolder: "Målmappen er en undermappe til mappen du ønsker å flytte."
@ -196,14 +219,14 @@ copyUrl: "Kopier URL"
rename: "Endre navn" rename: "Endre navn"
avatar: "Avatar" avatar: "Avatar"
banner: "Banner" banner: "Banner"
doNothing: "Gjør ingenting" doNothing: "Ignorer"
accept: "Tillatt" accept: "Tillatt"
reject: "Avslå" reject: "Avslå"
instanceName: "Servernavn" instanceName: "Servernavn"
instanceDescription: "Serverbeskrivelse" instanceDescription: "Serverbeskrivelse"
thisYear: "I år" thisYear: "År"
thisMonth: "Måned" thisMonth: "Måned"
today: "I dag" today: "Dag"
dayX: "{day}" dayX: "{day}"
monthX: "{month}" monthX: "{month}"
yearX: "{year}" yearX: "{year}"
@ -216,9 +239,10 @@ registration: "Registrer"
enableRegistration: "Aktiver registrering av nye brukere" enableRegistration: "Aktiver registrering av nye brukere"
invite: "Inviter" invite: "Inviter"
basicInfo: "Grunnleggende informasjon" basicInfo: "Grunnleggende informasjon"
pinnedUsers: "Festete brukrere" pinnedUsers: "Festede brukrere"
pinnedUsersDescription: "Liste over brukernavn atskilt med linjeskift som skal festes i \"Utforsk\" fanen." pinnedUsersDescription: "Liste over brukernavn atskilt med linjeskift som skal festes i \"Utforsk\" fanen."
pinnedPages: "Festete sider" pinnedPages: "Festede sider"
pinnedNotes: "Festet note"
hcaptcha: "hCaptcha" hcaptcha: "hCaptcha"
enableHcaptcha: "Aktiver hCaptcha" enableHcaptcha: "Aktiver hCaptcha"
recaptcha: "reCAPTCHA" recaptcha: "reCAPTCHA"
@ -245,25 +269,37 @@ available: "Tilgjengelig"
unavailable: "Utilgjengelig" unavailable: "Utilgjengelig"
tooShort: "For kort" tooShort: "For kort"
tooLong: "For langt" tooLong: "For langt"
weakPassword: "Svakt passord"
normalPassword: "Gjennomsnittlig passord"
strongPassword: "Sterkt passord"
signinWith: "Logg inn med {x}"
signinFailed: "Kunne ikke logge inn. Det oppgitte brukernavnet eller passordet er feil."
or: "eller" or: "eller"
language: "Språk" language: "Språk"
aboutX: "Om {x}" aboutX: "Om {x}"
category: "Kategorier" category: "Kategori"
createAccount: "Opprett konto" createAccount: "Opprett konto"
openImageInNewTab: "Åpne bilder i ny fane"
clientSettings: "Klientinnstillinger"
accountSettings: "Kontoinnstillinger"
objectStorageRegion: "Region" objectStorageRegion: "Region"
objectStorageUseSSL: "Bruk SSL" objectStorageUseSSL: "Bruk SSL"
objectStorageUseProxy: "Bruk Proxy" objectStorageUseProxy: "Bruk Proxy"
deleteAll: "Slett alt" deleteAll: "Slett alt"
newNoteRecived: "Det er nye notes"
listen: "Lytt" listen: "Lytt"
none: "Ingen" none: "Ingen"
volume: "Volum"
chooseEmoji: "Velg emoji" chooseEmoji: "Velg emoji"
recentUsed: "Sist brukte" recentUsed: "Sist brukte"
install: "Installer" install: "Installer"
uninstall: "Avinstaller"
nothing: "Ingenting" nothing: "Ingenting"
deleteAllFiles: "Slett alle filer" deleteAllFiles: "Slett alle filer"
deleteAllFilesConfirm: "Vil du slette alle filer?" deleteAllFilesConfirm: "Er du sikker på at du vil slette alle filer?"
userSuspended: "Denne brukeren har blitt suspendert."
accountDeleted: "Kontoen blir slettet" accountDeleted: "Kontoen blir slettet"
accountDeletedDescription: "Denne kontoen blir slettet" accountDeletedDescription: "Denne kontoen har blitt slettet."
menu: "Meny" menu: "Meny"
poll: "Avstemning" poll: "Avstemning"
description: "Beskrivelse" description: "Beskrivelse"
@ -274,6 +310,7 @@ small: "Liten"
notificationType: "Varseltype" notificationType: "Varseltype"
edit: "Rediger" edit: "Rediger"
email: "E-post" email: "E-post"
smtpHost: "Vert"
smtpUser: "Brukernavn" smtpUser: "Brukernavn"
smtpPass: "Passord" smtpPass: "Passord"
userSaysSomething: "{name} sa noe" userSaysSomething: "{name} sa noe"
@ -289,16 +326,24 @@ reportAbuse: "Rappoter"
send: "Send" send: "Send"
openInNewTab: "Åpne i ny fane" openInNewTab: "Åpne i ny fane"
waitingFor: "Venter på {x}" waitingFor: "Venter på {x}"
random: "Tilfeldig"
system: "System" system: "System"
desktop: "Skrivebord"
i18nInfo: "Misskey oversettes til flere språk av frivillige. Du kan hjelpe til på {link}."
followingCount: "Følger" followingCount: "Følger"
followersCount: "Følgere" followersCount: "Følgere"
yes: "Ja" yes: "Ja"
no: "Nei" no: "Nei"
contact: "Kontakt"
developer: "Utvikler"
makeExplorable: "Gjør konto synlig i \"Utforsk\""
makeExplorableDescription: "Hvis du slår av dette, vises ikke kontoen din i \"Utforsk\" delen."
left: "Venstre" left: "Venstre"
saveAs: "Lagre som" saveAs: "Lagre som"
value: "Verdi" value: "Verdi"
deleteConfirm: "Vil du slette?" deleteConfirm: "Vil du slette?"
invalidValue: "Verdien er ugyldig." invalidValue: "Verdien er ugyldig."
closeAccount: "Avslutt konto"
emailNotification: "E-postvarsler" emailNotification: "E-postvarsler"
inChannelSearch: "Søk i kanal" inChannelSearch: "Søk i kanal"
clear: "Tøm" clear: "Tøm"
@ -312,17 +357,23 @@ accounts: "Kontoer"
switch: "Bytt" switch: "Bytt"
gallery: "Galleri" gallery: "Galleri"
ads: "Annonser" ads: "Annonser"
memo: "Notat"
high: "Høy" high: "Høy"
low: "Lav" low: "Lav"
sent: "Send" sent: "Sendt"
received: "Mottatt"
learnMore: "Les mer" learnMore: "Les mer"
misskeyUpdated: "Misskey har blitt oppdatert!"
translate: "Oversett" translate: "Oversett"
translatedFrom: "Oversatt fra {x}"
unread: "Ulest" unread: "Ulest"
manageAccounts: "Administrer konto" manageAccounts: "Administrer konto"
classic: "Klassisk" classic: "Klassisk"
muteThread: "Skjul denne tråden" muteThread: "Skjul denne tråden"
unmuteThread: "Vis denne tråden" unmuteThread: "Vis denne tråden"
continueThread: "Vis fortsettelse av tråden"
hide: "Skjul" hide: "Skjul"
smartphone: "Smarttelefon"
tablet: "Nettbrett" tablet: "Nettbrett"
auto: "Automatisk" auto: "Automatisk"
size: "Størrelse" size: "Størrelse"
@ -338,10 +389,10 @@ check: "Sjekk"
deleteAccount: "Slett konto" deleteAccount: "Slett konto"
document: "Dokumenter" document: "Dokumenter"
logoutConfirm: "Vil du logge ut?" logoutConfirm: "Vil du logge ut?"
pleaseSelect: "Vennligst velg" pleaseSelect: "Velg et alternativ"
type: "Type" type: "Type"
beta: "Beta" beta: "Beta"
account: "Kontoer" account: "Konto"
move: "Flytt" move: "Flytt"
pushNotification: "Push-varsler" pushNotification: "Push-varsler"
tools: "Verktøy" tools: "Verktøy"
@ -357,6 +408,7 @@ role: "Rolle"
color: "Farge" color: "Farge"
youCannotCreateAnymore: "Du kan ikke opprette flere." youCannotCreateAnymore: "Du kan ikke opprette flere."
cannotPerformTemporary: "Midlertidig utilgjengelig" cannotPerformTemporary: "Midlertidig utilgjengelig"
achievements: "Prestasjoner"
thisPostMayBeAnnoyingCancel: "Avbryt" thisPostMayBeAnnoyingCancel: "Avbryt"
exploreOtherServers: "Utforsk andre severe" exploreOtherServers: "Utforsk andre severe"
letsLookAtTimeline: "La oss se på tidslinje" letsLookAtTimeline: "La oss se på tidslinje"
@ -400,7 +452,7 @@ _achievements:
_justPlainLucky: _justPlainLucky:
title: "Rett og slett heldig" title: "Rett og slett heldig"
_setNameToSyuilo: _setNameToSyuilo:
description: "Du har satt navnet ditt til \"syuilo\"" description: "Du satte navnet ditt til \"syuilo\""
_passedSinceAccountCreated1: _passedSinceAccountCreated1:
title: "Ett års jubileum" title: "Ett års jubileum"
description: "Det har gått ett år siden kontoen din ble opprettet" description: "Det har gått ett år siden kontoen din ble opprettet"
@ -468,15 +520,17 @@ _theme:
key: "Nøkkel" key: "Nøkkel"
keys: keys:
link: "Lenke" link: "Lenke"
renote: "Renote"
_sfx: _sfx:
note: "Notes"
notification: "Varsler" notification: "Varsler"
_ago: _ago:
future: "Fremitid" future: "Fremitid"
justNow: "Akkurat nå" justNow: "Akkurat nå"
secondsAgo: "{n} sekunder siden" secondsAgo: "{n}s siden"
minutesAgo: "{n} minutter siden" minutesAgo: "{n}m siden"
hoursAgo: "{n} timer siden" hoursAgo: "{n}t siden"
daysAgo: "{n} dager siden" daysAgo: "{n}d siden"
weeksAgo: "{n} uker siden" weeksAgo: "{n} uker siden"
monthsAgo: "{n} måneder siden" monthsAgo: "{n} måneder siden"
yearsAgo: "{n} år siden" yearsAgo: "{n} år siden"
@ -579,10 +633,12 @@ _notification:
_types: _types:
follow: "Følg" follow: "Følg"
reply: "Svar" reply: "Svar"
renote: "Renote"
quote: "Sitat" quote: "Sitat"
reaction: "Reaksjon" reaction: "Reaksjon"
_actions: _actions:
reply: "Svar" reply: "Svar"
renote: "Renote"
_deck: _deck:
swapLeft: "Flytt til venstre" swapLeft: "Flytt til venstre"
swapRight: "Flytt til høyre" swapRight: "Flytt til høyre"

View file

@ -1055,6 +1055,11 @@ failedToPreviewUrl: "無法預覽"
update: "更新" update: "更新"
rolesThatCanBeUsedThisEmojiAsReaction: "可以當成反應使用的角色" rolesThatCanBeUsedThisEmojiAsReaction: "可以當成反應使用的角色"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "如果是未指定角色的情況,則任何人都可以被當成反應來使用。" rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "如果是未指定角色的情況,則任何人都可以被當成反應來使用。"
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "角色必須是公開的角色。"
cancelReactionConfirm: "要取消做出的反應嗎?"
changeReactionConfirm: "要變更做出的反應嗎?"
later: "稍後再說"
goToMisskey: "往Misskey"
_initialAccountSetting: _initialAccountSetting:
accountCreated: "帳戶已建立完成!" accountCreated: "帳戶已建立完成!"
letsStartAccountSetup: "來進行帳戶的初始設定吧。" letsStartAccountSetup: "來進行帳戶的初始設定吧。"
@ -1069,6 +1074,7 @@ _initialAccountSetting:
haveFun: "盡情享受{name}吧!" haveFun: "盡情享受{name}吧!"
ifYouNeedLearnMore: "關於如何使用{name}(Misskey)的詳細資訊,請見{link}。" ifYouNeedLearnMore: "關於如何使用{name}(Misskey)的詳細資訊,請見{link}。"
skipAreYouSure: "要略過初始設定嗎?" skipAreYouSure: "要略過初始設定嗎?"
laterAreYouSure: "稍後再重新進行初始設定嗎?"
_serverRules: _serverRules:
description: "設定伺服器的簡要規則,在新的註冊之前顯示。建議的內容是使用條款的摘要。" description: "設定伺服器的簡要規則,在新的註冊之前顯示。建議的內容是使用條款的摘要。"
_accountMigration: _accountMigration:

View file

@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "13.13.0-beta.5", "version": "13.13.0-beta.6",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",

View file

@ -1,7 +1,8 @@
<template> <template>
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"> <div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
<input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter"> <input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter">
<div ref="emojisEl" class="emojis"> <!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 -->
<div ref="emojisEl" class="emojis" tabindex="-1">
<section class="result"> <section class="result">
<div v-if="searchResultCustom.length > 0" class="body"> <div v-if="searchResultCustom.length > 0" class="body">
<button <button
@ -101,7 +102,7 @@ import { isTouchUsing } from '@/scripts/touch';
import { deviceKind } from '@/scripts/device-kind'; import { deviceKind } from '@/scripts/device-kind';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { customEmojiCategories, customEmojis } from '@/custom-emojis'; import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis';
import { $i } from '@/account'; import { $i } from '@/account';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
@ -337,7 +338,7 @@ function done(query?: string): boolean | void {
if (query == null || typeof query !== 'string') return; if (query == null || typeof query !== 'string') return;
const q2 = query.replace(/:/g, ''); const q2 = query.replace(/:/g, '');
const exactMatchCustom = customEmojis.value.find(emoji => emoji.name === q2); const exactMatchCustom = customEmojisMap.get(q2);
if (exactMatchCustom) { if (exactMatchCustom) {
chosen(exactMatchCustom); chosen(exactMatchCustom);
return true; return true;

View file

@ -205,8 +205,11 @@ const isMyRenote = $i && ($i.id === note.userId);
const showContent = ref(false); const showContent = ref(false);
const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null; const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null;
const isLong = (appearNote.cw == null && appearNote.text != null && ( const isLong = (appearNote.cw == null && appearNote.text != null && (
(appearNote.text.includes('$[x2')) ||
(appearNote.text.includes('$[x3')) || (appearNote.text.includes('$[x3')) ||
(appearNote.text.includes('$[x4')) || (appearNote.text.includes('$[x4')) ||
(appearNote.text.includes('$[scale')) ||
(appearNote.text.includes('$[position')) ||
(appearNote.text.split('\n').length > 9) || (appearNote.text.split('\n').length > 9) ||
(appearNote.text.length > 500) || (appearNote.text.length > 500) ||
(appearNote.files.length >= 5) || (appearNote.files.length >= 5) ||

View file

@ -7,7 +7,7 @@
import { computed } from 'vue'; import { computed } from 'vue';
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy'; import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { customEmojis } from '@/custom-emojis'; import { customEmojisMap } from '@/custom-emojis';
const props = defineProps<{ const props = defineProps<{
name: string; name: string;
@ -26,7 +26,7 @@ const rawUrl = computed(() => {
return props.url; return props.url;
} }
if (isLocal.value) { if (isLocal.value) {
return customEmojis.value.find(x => x.name === customEmojiName.value)?.url ?? null; return customEmojisMap.get(customEmojiName.value)?.url ?? null;
} }
return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; return props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`;
}); });

View file

@ -14,6 +14,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue'; import { onMounted, onUnmounted, provide, inject, Ref, ref, watch } from 'vue';
import { $$ } from 'vue/macros';
import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@/const'; import { CURRENT_STICKY_BOTTOM, CURRENT_STICKY_TOP } from '@/const';
const rootEl = $shallowRef<HTMLElement>(); const rootEl = $shallowRef<HTMLElement>();
@ -83,8 +84,8 @@ onMounted(() => {
onUnmounted(() => { onUnmounted(() => {
observer.disconnect(); observer.disconnect();
}); });
defineExpose({
rootEl: $$(rootEl),
});
</script> </script>
<style lang="scss" module>
</style>

View file

@ -1,4 +1,4 @@
import { shallowRef, computed, markRaw } from 'vue'; import { shallowRef, computed, markRaw, watch } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { api, apiGet } from './os'; import { api, apiGet } from './os';
import { useStream } from '@/stream'; import { useStream } from '@/stream';
@ -16,6 +16,14 @@ export const customEmojiCategories = computed<[ ...string[], null ]>(() => {
return markRaw([...Array.from(categories), null]); return markRaw([...Array.from(categories), null]);
}); });
export const customEmojisMap = new Map<string, Misskey.entities.CustomEmoji>();
watch(customEmojis, emojis => {
customEmojisMap.clear();
for (const emoji of emojis) {
customEmojisMap.set(emoji.name, emoji);
}
}, { immediate: true });
// TODO: ここら辺副作用なのでいい感じにする // TODO: ここら辺副作用なのでいい感じにする
const stream = useStream(); const stream = useStream();

View file

@ -1,44 +1,42 @@
<template> <template>
<div class="kmwsukvl"> <div :class="$style.root">
<div class="body"> <div :class="$style.top">
<div class="top"> <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<div class="banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <button class="_button" :class="$style.instance" @click="openInstanceMenu">
<button v-click-anime class="item _button instance" @click="openInstanceMenu"> <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/>
</button> </button>
</div> </div>
<div class="middle"> <div :class="$style.middle">
<MkA v-click-anime class="item index" activeClass="active" to="/" exact> <MkA :class="$style.item" :activeClass="$style.active" to="/" exact>
<i class="icon ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> <i :class="$style.itemIcon" class="ti ti-home ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.timeline }}</span>
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" :class="$style.divider"></div>
<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" activeClass="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> <component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" class="_button" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]" :activeClass="$style.active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}">
<i class="icon ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span>
<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon _indicatorCircle"></i></span> <span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</component> </component>
</template> </template>
<div class="divider"></div> <div :class="$style.divider"></div>
<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" activeClass="active" to="/admin"> <MkA v-if="$i.isAdmin || $i.isModerator" :class="$style.item" :activeClass="$style.active" to="/admin">
<i class="icon ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
</MkA> </MkA>
<button v-click-anime class="item _button" @click="more"> <button :class="$style.item" class="_button" @click="more">
<i class="icon ti ti-grid-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <i :class="$style.itemIcon" class="ti ti-grid-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" class="indicator"><i class="icon _indicatorCircle"></i></span> <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</button> </button>
<MkA v-click-anime class="item" activeClass="active" to="/settings"> <MkA :class="$style.item" :activeClass="$style.active" to="/settings">
<i class="icon ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> <i :class="$style.itemIcon" class="ti ti-settings ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.settings }}</span>
</MkA> </MkA>
</div> </div>
<div class="bottom"> <div :class="$style.bottom">
<button class="item _button post" data-cy-open-post-form @click="os.post"> <button class="_button" :class="$style.post" data-cy-open-post-form @click="os.post">
<i class="icon ti ti-pencil ti-fw"></i><span class="text">{{ i18n.ts.note }}</span> <i :class="$style.postIcon" class="ti ti-pencil ti-fw"></i><span style="position: relative;">{{ i18n.ts.note }}</span>
</button> </button>
<button v-click-anime class="item _button account" @click="openAccountMenu"> <button class="_button" :class="$style.account" @click="openAccountMenu">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text _nowrap" :user="$i"/> <MkAvatar :user="$i" :class="$style.avatar"/><MkAcct :class="$style.acct" class="_nowrap" :user="$i"/>
</button> </button>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -73,13 +71,13 @@ function more() {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" module>
.kmwsukvl { .root {
> .body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
}
> .top { .top {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 1; z-index: 1;
@ -87,8 +85,9 @@ function more() {
background: var(--X14); background: var(--X14);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(8px));
backdrop-filter: var(--blur, blur(8px)); backdrop-filter: var(--blur, blur(8px));
}
> .banner { .banner {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -98,31 +97,31 @@ function more() {
background-position: center center; background-position: center center;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); -webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
} }
> .instance { .instance {
position: relative; position: relative;
display: block; display: block;
text-align: center; text-align: center;
width: 100%; width: 100%;
}
> .icon { .instanceIcon {
display: inline-block; display: inline-block;
width: 38px; width: 38px;
aspect-ratio: 1; aspect-ratio: 1;
} }
}
}
> .bottom { .bottom {
position: sticky; position: sticky;
bottom: 0; bottom: 0;
padding: 20px 0; padding: 20px 0;
background: var(--X14); background: var(--X14);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(8px));
backdrop-filter: var(--blur, blur(8px)); backdrop-filter: var(--blur, blur(8px));
}
> .post { .post {
position: relative; position: relative;
display: block; display: block;
width: 100%; width: 100%;
@ -151,20 +150,16 @@ function more() {
background: var(--accentLighten); background: var(--accentLighten);
} }
} }
}
> .icon { .postIcon {
position: relative; position: relative;
margin-left: 30px; margin-left: 30px;
margin-right: 8px; margin-right: 8px;
width: 32px; width: 32px;
} }
> .text { .account {
position: relative;
}
}
> .account {
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
@ -173,33 +168,33 @@ function more() {
text-align: left; text-align: left;
box-sizing: border-box; box-sizing: border-box;
margin-top: 16px; margin-top: 16px;
}
> .avatar { .avatar {
display: block; display: block;
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
width: 32px; width: 32px;
aspect-ratio: 1; aspect-ratio: 1;
margin-right: 8px; margin-right: 8px;
} }
> .text { .acct {
display: block; display: block;
flex-shrink: 1; flex-shrink: 1;
padding-right: 8px; padding-right: 8px;
} }
}
}
> .middle { .middle {
flex: 1; flex: 1;
}
> .divider { .divider {
margin: 16px 16px; margin: 16px 16px;
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
} }
> .item { .item {
position: relative; position: relative;
display: block; display: block;
padding-left: 24px; padding-left: 24px;
@ -212,26 +207,6 @@ function more() {
box-sizing: border-box; box-sizing: border-box;
color: var(--navFg); color: var(--navFg);
> .icon {
position: relative;
width: 32px;
margin-right: 8px;
}
> .indicator {
position: absolute;
top: 0;
left: 20px;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;
}
> .text {
position: relative;
font-size: 0.9em;
}
&:hover { &:hover {
text-decoration: none; text-decoration: none;
color: var(--navHoverFg); color: var(--navHoverFg);
@ -257,8 +232,25 @@ function more() {
background: var(--accentedBg); background: var(--accentedBg);
} }
} }
} }
}
} .itemIcon {
position: relative;
width: 32px;
margin-right: 8px;
}
.itemIndicator {
position: absolute;
top: 0;
left: 20px;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;
}
.itemText {
position: relative;
font-size: 0.9em;
} }
</style> </style>

View file

@ -1,51 +1,50 @@
<template> <template>
<div class="mvcprjjd" :class="{ iconOnly }"> <div :class="[$style.root, { [$style.iconOnly]: iconOnly }]">
<div class="body"> <div :class="$style.body">
<div class="top"> <div :class="$style.top">
<div class="banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div> <div :class="$style.banner" :style="{ backgroundImage: `url(${ instance.bannerUrl })` }"></div>
<button v-click-anime v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="item _button instance" @click="openInstanceMenu"> <button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
<img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/> <img :src="instance.iconUrl || instance.faviconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon"/>
</button> </button>
</div> </div>
<div class="middle"> <div :class="$style.middle">
<MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.timeline" class="item index" activeClass="active" to="/" exact> <MkA v-tooltip.noDelay.right="i18n.ts.timeline" :class="$style.item" :activeClass="$style.active" to="/" exact>
<i class="icon ti ti-home ti-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> <i :class="$style.itemIcon" class="ti ti-home ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.timeline }}</span>
</MkA> </MkA>
<template v-for="item in menu"> <template v-for="item in menu">
<div v-if="item === '-'" class="divider"></div> <div v-if="item === '-'" :class="$style.divider"></div>
<component <component
:is="navbarItemDef[item].to ? 'MkA' : 'button'" :is="navbarItemDef[item].to ? 'MkA' : 'button'"
v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)"
v-click-anime
v-tooltip.noDelay.right="navbarItemDef[item].title" v-tooltip.noDelay.right="navbarItemDef[item].title"
class="item _button" class="_button"
:class="[item, { active: navbarItemDef[item].active }]" :class="[$style.item, { [$style.active]: navbarItemDef[item].active }]"
activeClass="active" :activeClass="$style.active"
:to="navbarItemDef[item].to" :to="navbarItemDef[item].to"
v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"
> >
<i class="icon ti-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ navbarItemDef[item].title }}</span> <i class="ti-fw" :class="[$style.itemIcon, navbarItemDef[item].icon]"></i><span :class="$style.itemText">{{ navbarItemDef[item].title }}</span>
<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon _indicatorCircle"></i></span> <span v-if="navbarItemDef[item].indicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</component> </component>
</template> </template>
<div class="divider"></div> <div :class="$style.divider"></div>
<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.noDelay.right="i18n.ts.controlPanel" class="item" activeClass="active" to="/admin"> <MkA v-if="$i.isAdmin || $i.isModerator" v-tooltip.noDelay.right="i18n.ts.controlPanel" :class="$style.item" :activeClass="$style.active" to="/admin">
<i class="icon ti ti-dashboard ti-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> <i :class="$style.itemIcon" class="ti ti-dashboard ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
</MkA> </MkA>
<button v-click-anime class="item _button" @click="more"> <button class="_button" :class="$style.item" @click="more">
<i class="icon ti ti-grid-dots ti-fw"></i><span class="text">{{ i18n.ts.more }}</span> <i :class="$style.itemIcon" class="ti ti-grid-dots ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
<span v-if="otherMenuItemIndicated" class="indicator"><i class="icon _indicatorCircle"></i></span> <span v-if="otherMenuItemIndicated" :class="$style.itemIndicator"><i class="_indicatorCircle"></i></span>
</button> </button>
<MkA v-click-anime v-tooltip.noDelay.right="i18n.ts.settings" class="item" activeClass="active" to="/settings"> <MkA v-tooltip.noDelay.right="i18n.ts.settings" :class="$style.item" :activeClass="$style.active" to="/settings">
<i class="icon ti ti-settings ti-fw"></i><span class="text">{{ i18n.ts.settings }}</span> <i :class="$style.itemIcon" class="ti ti-settings ti-fw"></i><span :class="$style.itemText">{{ i18n.ts.settings }}</span>
</MkA> </MkA>
</div> </div>
<div class="bottom"> <div :class="$style.bottom">
<button v-tooltip.noDelay.right="i18n.ts.note" class="item _button post" data-cy-open-post-form @click="os.post"> <button v-tooltip.noDelay.right="i18n.ts.note" class="_button" :class="[$style.post]" data-cy-open-post-form @click="os.post">
<i class="icon ti ti-pencil ti-fw"></i><span class="text">{{ i18n.ts.note }}</span> <i class="ti ti-pencil ti-fw" :class="$style.postIcon"></i><span :class="$style.postText">{{ i18n.ts.note }}</span>
</button> </button>
<button v-click-anime v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="item _button account" @click="openAccountMenu"> <button v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu">
<MkAvatar :user="$i" class="avatar"/><MkAcct class="text _nowrap" :user="$i"/> <MkAvatar :user="$i" :class="$style.avatar"/><MkAcct class="_nowrap" :class="$style.acct" :user="$i"/>
</button> </button>
</div> </div>
</div> </div>
@ -99,36 +98,39 @@ function more(ev: MouseEvent) {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" module>
.mvcprjjd { .root {
$nav-width: 250px; --nav-width: 250px;
$nav-icon-only-width: 80px; --nav-icon-only-width: 80px;
flex: 0 0 $nav-width; flex: 0 0 var(--nav-width);
width: $nav-width; width: var(--nav-width);
box-sizing: border-box; box-sizing: border-box;
}
> .body { .body {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
z-index: 1001; z-index: 1001;
width: $nav-icon-only-width; width: var(--nav-icon-only-width);
height: 100dvh; height: 100dvh;
box-sizing: border-box; box-sizing: border-box;
overflow: auto; overflow: auto;
overflow-x: clip; overflow-x: clip;
overscroll-behavior: contain;
background: var(--navBg); background: var(--navBg);
contain: strict; contain: strict;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
}
.root:not(.iconOnly) {
.body {
width: var(--nav-width);
} }
&:not(.iconOnly) { .top {
> .body {
width: $nav-width;
> .top {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 1; z-index: 1;
@ -136,8 +138,9 @@ function more(ev: MouseEvent) {
background: var(--X14); background: var(--X14);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(8px));
backdrop-filter: var(--blur, blur(8px)); backdrop-filter: var(--blur, blur(8px));
}
> .banner { .banner {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -149,29 +152,29 @@ function more(ev: MouseEvent) {
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%); mask-image: linear-gradient(0deg, rgba(0,0,0,0) 15%, rgba(0,0,0,0.75) 100%);
} }
> .instance { .instance {
position: relative; position: relative;
display: block; display: block;
text-align: center; text-align: center;
width: 100%; width: 100%;
}
> .icon { .instanceIcon {
display: inline-block; display: inline-block;
width: 38px; width: 38px;
aspect-ratio: 1; aspect-ratio: 1;
} }
}
}
> .bottom { .bottom {
position: sticky; position: sticky;
bottom: 0; bottom: 0;
padding: 20px 0; padding: 20px 0;
background: var(--X14); background: var(--X14);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(8px));
backdrop-filter: var(--blur, blur(8px)); backdrop-filter: var(--blur, blur(8px));
}
> .post { .post {
position: relative; position: relative;
display: block; display: block;
width: 100%; width: 100%;
@ -200,20 +203,20 @@ function more(ev: MouseEvent) {
background: var(--accentLighten); background: var(--accentLighten);
} }
} }
}
> .icon { .postIcon {
position: relative; position: relative;
margin-left: 30px; margin-left: 30px;
margin-right: 8px; margin-right: 8px;
width: 32px; width: 32px;
} }
> .text { .postText {
position: relative; position: relative;
} }
}
> .account { .account {
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
@ -222,8 +225,9 @@ function more(ev: MouseEvent) {
text-align: left; text-align: left;
box-sizing: border-box; box-sizing: border-box;
margin-top: 16px; margin-top: 16px;
}
> .avatar { .avatar {
display: block; display: block;
flex-shrink: 0; flex-shrink: 0;
position: relative; position: relative;
@ -232,23 +236,22 @@ function more(ev: MouseEvent) {
margin-right: 8px; margin-right: 8px;
} }
> .text { .acct {
display: block; display: block;
flex-shrink: 1; flex-shrink: 1;
padding-right: 8px; padding-right: 8px;
} }
}
}
> .middle { .middle {
flex: 1; flex: 1;
}
> .divider { .divider {
margin: 16px 16px; margin: 16px 16px;
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
} }
> .item { .item {
position: relative; position: relative;
display: block; display: block;
padding-left: 30px; padding-left: 30px;
@ -261,26 +264,6 @@ function more(ev: MouseEvent) {
box-sizing: border-box; box-sizing: border-box;
color: var(--navFg); color: var(--navFg);
> .icon {
position: relative;
width: 32px;
margin-right: 8px;
}
> .indicator {
position: absolute;
top: 0;
left: 20px;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;
}
> .text {
position: relative;
font-size: 0.9em;
}
&:hover { &:hover {
text-decoration: none; text-decoration: none;
color: var(--navHoverFg); color: var(--navHoverFg);
@ -309,18 +292,37 @@ function more(ev: MouseEvent) {
} }
} }
} }
}
} .itemIcon {
position: relative;
width: 32px;
margin-right: 8px;
} }
&.iconOnly { .itemIndicator {
flex: 0 0 $nav-icon-only-width; position: absolute;
width: $nav-icon-only-width; top: 0;
left: 20px;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;
}
> .body { .itemText {
width: $nav-icon-only-width; position: relative;
font-size: 0.9em;
}
}
> .top { .root.iconOnly {
flex: 0 0 var(--nav-icon-only-width);
width: var(--nav-icon-only-width);
.body {
width: var(--nav-icon-only-width);
}
.top {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 1; z-index: 1;
@ -328,29 +330,30 @@ function more(ev: MouseEvent) {
background: var(--X14); background: var(--X14);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(8px));
backdrop-filter: var(--blur, blur(8px)); backdrop-filter: var(--blur, blur(8px));
}
> .instance { .instance {
display: block; display: block;
text-align: center; text-align: center;
width: 100%; width: 100%;
}
> .icon { .instanceIcon {
display: inline-block; display: inline-block;
width: 30px; width: 30px;
aspect-ratio: 1; aspect-ratio: 1;
} }
}
}
> .bottom { .bottom {
position: sticky; position: sticky;
bottom: 0; bottom: 0;
padding: 20px 0; padding: 20px 0;
background: var(--X14); background: var(--X14);
-webkit-backdrop-filter: var(--blur, blur(8px)); -webkit-backdrop-filter: var(--blur, blur(8px));
backdrop-filter: var(--blur, blur(8px)); backdrop-filter: var(--blur, blur(8px));
}
> .post { .post {
display: block; display: block;
position: relative; position: relative;
width: 100%; width: 100%;
@ -378,69 +381,50 @@ function more(ev: MouseEvent) {
background: var(--accentLighten); background: var(--accentLighten);
} }
} }
}
> .icon { .postIcon {
position: relative; position: relative;
color: var(--fgOnAccent); color: var(--fgOnAccent);
} }
> .text { .postText {
display: none; display: none;
} }
}
> .account { .account {
display: block; display: block;
text-align: center; text-align: center;
width: 100%; width: 100%;
}
> .avatar { .avatar {
display: inline-block; display: inline-block;
width: 38px; width: 38px;
aspect-ratio: 1; aspect-ratio: 1;
} }
> .text { .acct {
display: none; display: none;
} }
}
}
> .middle { .middle {
flex: 1; flex: 1;
}
> .divider { .divider {
margin: 8px auto; margin: 8px auto;
width: calc(100% - 32px); width: calc(100% - 32px);
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
} }
> .item { .item {
display: block; display: block;
position: relative; position: relative;
padding: 18px 0; padding: 18px 0;
width: 100%; width: 100%;
text-align: center; text-align: center;
> .icon {
display: block;
margin: 0 auto;
opacity: 0.7;
}
> .text {
display: none;
}
> .indicator {
position: absolute;
top: 6px;
left: 24px;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;
}
&:hover, &.active { &:hover, &.active {
text-decoration: none; text-decoration: none;
color: var(--accent); color: var(--accent);
@ -460,13 +444,30 @@ function more(ev: MouseEvent) {
background: var(--accentedBg); background: var(--accentedBg);
} }
> .icon, > .text { > .icon,
> .text {
opacity: 1; opacity: 1;
} }
} }
} }
.itemIcon {
display: block;
margin: 0 auto;
opacity: 0.7;
} }
.itemText {
display: none;
} }
.itemIndicator {
position: absolute;
top: 6px;
left: 24px;
color: var(--navIndicator);
font-size: 8px;
animation: blink 1s infinite;
} }
} }
</style> </style>

View file

@ -306,6 +306,7 @@ async function deleteProfile() {
display: flex; display: flex;
overflow-x: auto; overflow-x: auto;
overflow-y: clip; overflow-y: clip;
overscroll-behavior: contain;
background: var(--deckBg); background: var(--deckBg);
&.center { &.center {

View file

@ -387,9 +387,8 @@ function onDrop(ev) {
.body { .body {
height: calc(100% - var(--deckColumnHeaderHeight)); height: calc(100% - var(--deckColumnHeaderHeight));
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; // Safari does not supports clip
overflow-x: clip; overflow-x: clip;
-webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
box-sizing: border-box; box-sizing: border-box;
container-type: size; container-type: size;
background-color: var(--bg); background-color: var(--bg);

View file

@ -2,14 +2,10 @@
<div :class="$style.root"> <div :class="$style.root">
<XSidebar v-if="!isMobile" :class="$style.sidebar"/> <XSidebar v-if="!isMobile" :class="$style.sidebar"/>
<MkStickyContainer :class="$style.contents"> <MkStickyContainer ref="contents" :class="$style.contents" style="container-type: inline-size;" @contextmenu.stop="onContextmenu">
<template #header><XStatusBars :class="$style.statusbars"/></template> <template #header><XStatusBars :class="$style.statusbars"/></template>
<main style="min-width: 0;" @contextmenu.stop="onContextmenu">
<div style="container-type: inline-size;">
<RouterView/> <RouterView/>
</div>
<div :class="$style.spacer"></div> <div :class="$style.spacer"></div>
</main>
</MkStickyContainer> </MkStickyContainer>
<div v-if="isDesktop" :class="$style.widgets"> <div v-if="isDesktop" :class="$style.widgets">
@ -84,8 +80,9 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineAsyncComponent, provide, onMounted, computed, ref, ComputedRef, watch, inject, Ref } from 'vue'; import { defineAsyncComponent, provide, onMounted, computed, ref, ComputedRef, watch, shallowRef, Ref } from 'vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import type MkStickyContainer from '@/components/global/MkStickyContainer.vue';
import { instanceName } from '@/config'; import { instanceName } from '@/config';
import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue';
import * as os from '@/os'; import * as os from '@/os';
@ -98,6 +95,7 @@ import { PageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata';
import { deviceKind } from '@/scripts/device-kind'; import { deviceKind } from '@/scripts/device-kind';
import { miLocalStorage } from '@/local-storage'; import { miLocalStorage } from '@/local-storage';
import { CURRENT_STICKY_BOTTOM } from '@/const'; import { CURRENT_STICKY_BOTTOM } from '@/const';
const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue'));
const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue'));
const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue'));
@ -115,6 +113,7 @@ window.addEventListener('resize', () => {
let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let pageMetadata = $ref<null | ComputedRef<PageMetadata>>();
const widgetsShowing = $ref(false); const widgetsShowing = $ref(false);
const navFooter = $shallowRef<HTMLElement>(); const navFooter = $shallowRef<HTMLElement>();
const contents = shallowRef<InstanceType<typeof MkStickyContainer>>();
provide('router', mainRouter); provide('router', mainRouter);
provideMetadataReceiver((info) => { provideMetadataReceiver((info) => {
@ -194,7 +193,10 @@ const onContextmenu = (ev) => {
}; };
function top() { function top() {
// TODO contents.value.rootEl.scrollTo({
top: 0,
behavior: 'smooth',
});
} }
let navFooterHeight = $ref(0); let navFooterHeight = $ref(0);
@ -278,6 +280,7 @@ $widgets-hide-threshold: 1090px;
min-width: 0; min-width: 0;
overflow: auto; overflow: auto;
overflow-y: scroll; overflow-y: scroll;
overscroll-behavior: contain;
background: var(--bg); background: var(--bg);
} }