Merge branch 'develop' into fetch
This commit is contained in:
commit
3a2d9f4823
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -31,6 +31,7 @@ You should also include the user name that made the change.
|
||||||
#### For users
|
#### For users
|
||||||
- ノートのウォッチ機能が削除されました
|
- ノートのウォッチ機能が削除されました
|
||||||
- アンケートに投票された際に通知が作成されなくなりました
|
- アンケートに投票された際に通知が作成されなくなりました
|
||||||
|
- ノートの数式埋め込みが削除されました
|
||||||
- 新たに動的なPagesを作ることはできなくなりました
|
- 新たに動的なPagesを作ることはできなくなりました
|
||||||
- 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。
|
- 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。
|
||||||
- AiScriptが0.12.2にアップデートされました
|
- AiScriptが0.12.2にアップデートされました
|
||||||
|
@ -61,12 +62,14 @@ You should also include the user name that made the change.
|
||||||
- Server: signToActivityPubGet is set to true by default @syuilo
|
- Server: signToActivityPubGet is set to true by default @syuilo
|
||||||
- Server: improve syslog performance @syuilo
|
- Server: improve syslog performance @syuilo
|
||||||
- Server: improve note scoring for featured notes @CyberRex0
|
- Server: improve note scoring for featured notes @CyberRex0
|
||||||
|
- Server: アンケート選択肢の文字数制限を緩和 @syuilo
|
||||||
|
- Server: improve stats api performance @syuilo
|
||||||
|
- Server: improve nodeinfo performance @syuilo
|
||||||
- Server: delete outdated notifications regularly to improve db performance @syuilo
|
- Server: delete outdated notifications regularly to improve db performance @syuilo
|
||||||
- Server: delete outdated hard-mutes regularly to improve db performance @syuilo
|
- Server: delete outdated hard-mutes regularly to improve db performance @syuilo
|
||||||
- Server: delete outdated notes of antenna regularly to improve db performance @syuilo
|
- Server: delete outdated notes of antenna regularly to improve db performance @syuilo
|
||||||
- Server: improve activitypub deliver performance @syuilo
|
- Server: improve activitypub deliver performance @syuilo
|
||||||
- Client: use tabler-icons instead of fontawesome to better design @syuilo
|
- Client: use tabler-icons instead of fontawesome to better design @syuilo
|
||||||
- Client: Add AiScript App widget
|
|
||||||
- Client: Add new gabber kick sounds (thanks for noizenecio)
|
- Client: Add new gabber kick sounds (thanks for noizenecio)
|
||||||
- Client: Add link to user RSS feed in profile menu @ssmucny
|
- Client: Add link to user RSS feed in profile menu @ssmucny
|
||||||
- Client: Compress non-animated PNG files @saschanaz
|
- Client: Compress non-animated PNG files @saschanaz
|
||||||
|
@ -74,15 +77,18 @@ You should also include the user name that made the change.
|
||||||
- Client: enhance dashboard of control panel @syuilo
|
- Client: enhance dashboard of control panel @syuilo
|
||||||
- Client: Vite is upgraded to v4 @syuilo, @tamaina
|
- Client: Vite is upgraded to v4 @syuilo, @tamaina
|
||||||
- Client: HMR is available while yarn dev @tamaina
|
- Client: HMR is available while yarn dev @tamaina
|
||||||
- Client: Make widgets of universal/classic sync between devices @tamaina
|
|
||||||
- Client: Implement the button to subscribe push notification @tamaina
|
- Client: Implement the button to subscribe push notification @tamaina
|
||||||
- Client: Implement the toggle to or not to close push notifications when notifications or messages are read @tamaina
|
- Client: Implement the toggle to or not to close push notifications when notifications or messages are read @tamaina
|
||||||
- Client: Improve RSS widget @tamaina
|
|
||||||
- Client: show Unicode emoji tooltip with its name in MkReactionsViewer.reaction @saschanaz
|
- Client: show Unicode emoji tooltip with its name in MkReactionsViewer.reaction @saschanaz
|
||||||
- Client: OpenSearch support @SoniEx2 @chaoticryptidz
|
- Client: OpenSearch support @SoniEx2 @chaoticryptidz
|
||||||
- Client: Support remote objects in search @SoniEx2
|
- Client: Support remote objects in search @SoniEx2
|
||||||
- Client: user activity page @syuilo
|
- Client: user activity page @syuilo
|
||||||
|
- Client: Make widgets of universal/classic sync between devices @tamaina
|
||||||
- Client: add user list widget @syuilo
|
- Client: add user list widget @syuilo
|
||||||
|
- Client: Add AiScript App widget
|
||||||
|
- Client: add profile widget @syuilo
|
||||||
|
- Client: add instance info widget @syuilo
|
||||||
|
- Client: Improve RSS widget @tamaina
|
||||||
- Client: add heatmap of daily active users to about page @syuilo
|
- Client: add heatmap of daily active users to about page @syuilo
|
||||||
- Client: introduce fluent emoji @syuilo
|
- Client: introduce fluent emoji @syuilo
|
||||||
- Client: add new theme @syuilo
|
- Client: add new theme @syuilo
|
||||||
|
@ -107,6 +113,7 @@ You should also include the user name that made the change.
|
||||||
- Server: アンテナタイムライン(ストリーミング)が、フォローしていないユーザーの鍵投稿も拾ってしまう @syuilo
|
- Server: アンテナタイムライン(ストリーミング)が、フォローしていないユーザーの鍵投稿も拾ってしまう @syuilo
|
||||||
- Client: 日付形式の文字列などがカスタム絵文字として表示されるのを修正 @syuilo
|
- Client: 日付形式の文字列などがカスタム絵文字として表示されるのを修正 @syuilo
|
||||||
- Client: case insensitive emoji search @saschanaz
|
- Client: case insensitive emoji search @saschanaz
|
||||||
|
- Client: 画面の幅が狭いとウィジェットドロワーを閉じる手段がなくなるのを修正 @syuilo
|
||||||
- Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina
|
- Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina
|
||||||
- Client: use proxied image for instance icon @syuilo
|
- Client: use proxied image for instance icon @syuilo
|
||||||
- Client: Webhookの編集画面で、内容を保存することができない問題を修正 @m-hayabusa
|
- Client: Webhookの編集画面で、内容を保存することができない問題を修正 @m-hayabusa
|
||||||
|
@ -115,6 +122,11 @@ You should also include the user name that made the change.
|
||||||
- Client: チャートのツールチップが画面に残ることがあるのを修正 @syuilo
|
- Client: チャートのツールチップが画面に残ることがあるのを修正 @syuilo
|
||||||
- Client: fix wrong link in tutorial @syuilo
|
- Client: fix wrong link in tutorial @syuilo
|
||||||
|
|
||||||
|
### Special thanks
|
||||||
|
- All contributors
|
||||||
|
- All who have created instances for the beta test
|
||||||
|
- All who participated in the beta test
|
||||||
|
|
||||||
## 12.119.1 (2022/12/03)
|
## 12.119.1 (2022/12/03)
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- Server: Mitigate AP reference chain DoS vector @skehmatics
|
- Server: Mitigate AP reference chain DoS vector @skehmatics
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM node:18.12.1-bullseye AS builder
|
FROM node:18.13.0-bullseye AS builder
|
||||||
|
|
||||||
ARG NODE_ENV=production
|
ARG NODE_ENV=production
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ COPY . ./
|
||||||
RUN git submodule update --init
|
RUN git submodule update --init
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
FROM node:18.12.1-bullseye-slim AS runner
|
FROM node:18.13.0-bullseye-slim AS runner
|
||||||
|
|
||||||
WORKDIR /misskey
|
WORKDIR /misskey
|
||||||
|
|
||||||
|
|
|
@ -1117,6 +1117,8 @@ _weekday:
|
||||||
friday: "الجمعة"
|
friday: "الجمعة"
|
||||||
saturday: "السبت"
|
saturday: "السبت"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "الملف التعريفي"
|
||||||
|
instanceInfo: "معلومات مثيل الخادم"
|
||||||
memo: "ملاحظة لاصقة"
|
memo: "ملاحظة لاصقة"
|
||||||
notifications: "الإشعارات"
|
notifications: "الإشعارات"
|
||||||
timeline: "الخيط الزمني"
|
timeline: "الخيط الزمني"
|
||||||
|
|
|
@ -1200,6 +1200,8 @@ _weekday:
|
||||||
friday: "শুক্রবার"
|
friday: "শুক্রবার"
|
||||||
saturday: "শনিবার"
|
saturday: "শনিবার"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "প্রোফাইল"
|
||||||
|
instanceInfo: "ইন্সট্যান্সের তথ্য"
|
||||||
memo: "স্টিকি নোট"
|
memo: "স্টিকি নোট"
|
||||||
notifications: "বিজ্ঞপ্তি"
|
notifications: "বিজ্ঞপ্তি"
|
||||||
timeline: "টাইমলাইন"
|
timeline: "টাইমলাইন"
|
||||||
|
|
|
@ -399,6 +399,8 @@ _antennaSources:
|
||||||
userList: "Publicacions d'una llista d'usuaris"
|
userList: "Publicacions d'una llista d'usuaris"
|
||||||
userGroup: "Publicacions d'usuaris d'un grup"
|
userGroup: "Publicacions d'usuaris d'un grup"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Perfil"
|
||||||
|
instanceInfo: "Informació del fitxer d'instal·lació"
|
||||||
notifications: "Notificacions"
|
notifications: "Notificacions"
|
||||||
timeline: "Línia de temps"
|
timeline: "Línia de temps"
|
||||||
activity: "Activitat"
|
activity: "Activitat"
|
||||||
|
|
|
@ -694,6 +694,8 @@ _weekday:
|
||||||
friday: "Pátek"
|
friday: "Pátek"
|
||||||
saturday: "Sobota"
|
saturday: "Sobota"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Váš profil"
|
||||||
|
instanceInfo: "Informace o instanci"
|
||||||
notifications: "Oznámení"
|
notifications: "Oznámení"
|
||||||
timeline: "Časová osa"
|
timeline: "Časová osa"
|
||||||
calendar: "Kalendář"
|
calendar: "Kalendář"
|
||||||
|
|
|
@ -1302,6 +1302,8 @@ _weekday:
|
||||||
friday: "Freitag"
|
friday: "Freitag"
|
||||||
saturday: "Samstag"
|
saturday: "Samstag"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Instanzinformationen"
|
||||||
memo: "Merkzettel"
|
memo: "Merkzettel"
|
||||||
notifications: "Benachrichtigungen"
|
notifications: "Benachrichtigungen"
|
||||||
timeline: "Chronik"
|
timeline: "Chronik"
|
||||||
|
|
|
@ -343,6 +343,8 @@ _antennaSources:
|
||||||
userList: "Σημειώματα από καθορισμένη λίστα μελών"
|
userList: "Σημειώματα από καθορισμένη λίστα μελών"
|
||||||
userGroup: "Σημειώματα από μέλη καθορισμένης ομάδας"
|
userGroup: "Σημειώματα από μέλη καθορισμένης ομάδας"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Προφίλ"
|
||||||
|
instanceInfo: "Πληροφορίες του instance"
|
||||||
notifications: "Ειδοποιήσεις"
|
notifications: "Ειδοποιήσεις"
|
||||||
timeline: "Χρονολόγιο"
|
timeline: "Χρονολόγιο"
|
||||||
calendar: "Ημερολόγιο"
|
calendar: "Ημερολόγιο"
|
||||||
|
|
|
@ -1302,6 +1302,8 @@ _weekday:
|
||||||
friday: "Friday"
|
friday: "Friday"
|
||||||
saturday: "Saturday"
|
saturday: "Saturday"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profile"
|
||||||
|
instanceInfo: "Instance Information"
|
||||||
memo: "Sticky notes"
|
memo: "Sticky notes"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
timeline: "Timeline"
|
timeline: "Timeline"
|
||||||
|
|
|
@ -1296,6 +1296,8 @@ _weekday:
|
||||||
friday: "Viernes"
|
friday: "Viernes"
|
||||||
saturday: "Sábado"
|
saturday: "Sábado"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Perfil"
|
||||||
|
instanceInfo: "información de la instancia"
|
||||||
memo: "Nota adhesiva"
|
memo: "Nota adhesiva"
|
||||||
notifications: "Notificaciones"
|
notifications: "Notificaciones"
|
||||||
timeline: "Linea de tiempo"
|
timeline: "Linea de tiempo"
|
||||||
|
|
|
@ -1289,6 +1289,8 @@ _weekday:
|
||||||
friday: "Vendredi"
|
friday: "Vendredi"
|
||||||
saturday: "Samedi"
|
saturday: "Samedi"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Informations sur l’instance"
|
||||||
memo: "Note collante"
|
memo: "Note collante"
|
||||||
notifications: "Notifications"
|
notifications: "Notifications"
|
||||||
timeline: "Fil"
|
timeline: "Fil"
|
||||||
|
|
|
@ -1206,6 +1206,8 @@ _weekday:
|
||||||
friday: "Jumat"
|
friday: "Jumat"
|
||||||
saturday: "Sabtu"
|
saturday: "Sabtu"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Informasi Instansi"
|
||||||
memo: "Catatan memo"
|
memo: "Catatan memo"
|
||||||
notifications: "Pemberitahuan"
|
notifications: "Pemberitahuan"
|
||||||
timeline: "Linimasa"
|
timeline: "Linimasa"
|
||||||
|
|
|
@ -1296,6 +1296,8 @@ _weekday:
|
||||||
friday: "Venerdì"
|
friday: "Venerdì"
|
||||||
saturday: "Sabato"
|
saturday: "Sabato"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profilo"
|
||||||
|
instanceInfo: "Informazioni sull'istanza"
|
||||||
memo: "Promemoria"
|
memo: "Promemoria"
|
||||||
notifications: "Notifiche"
|
notifications: "Notifiche"
|
||||||
timeline: "Timeline"
|
timeline: "Timeline"
|
||||||
|
|
|
@ -1335,6 +1335,8 @@ _weekday:
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
|
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "プロフィール"
|
||||||
|
instanceInfo: "インスタンス情報"
|
||||||
memo: "付箋"
|
memo: "付箋"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
timeline: "タイムライン"
|
timeline: "タイムライン"
|
||||||
|
|
|
@ -1295,6 +1295,8 @@ _weekday:
|
||||||
friday: "金曜日"
|
friday: "金曜日"
|
||||||
saturday: "土曜日"
|
saturday: "土曜日"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "プロフィール"
|
||||||
|
instanceInfo: "インスタンス情報"
|
||||||
memo: "付箋"
|
memo: "付箋"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
timeline: "タイムライン"
|
timeline: "タイムライン"
|
||||||
|
|
|
@ -73,6 +73,7 @@ _sfx:
|
||||||
_permissions:
|
_permissions:
|
||||||
"write:account": "Ẓreg talɣut n umiḍan-ik·im"
|
"write:account": "Ẓreg talɣut n umiḍan-ik·im"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Amaɣnu"
|
||||||
notifications: "Ilɣuyen"
|
notifications: "Ilɣuyen"
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "Fren tabdart"
|
chooseList: "Fren tabdart"
|
||||||
|
|
|
@ -69,6 +69,7 @@ _mfm:
|
||||||
_sfx:
|
_sfx:
|
||||||
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "ಪ್ರೊಫೈಲು"
|
||||||
notifications: "ಅಧಿಸೂಚನೆಗಳು"
|
notifications: "ಅಧಿಸೂಚನೆಗಳು"
|
||||||
timeline: "ಸಮಯಸಾಲು"
|
timeline: "ಸಮಯಸಾಲು"
|
||||||
_cw:
|
_cw:
|
||||||
|
|
|
@ -1302,6 +1302,8 @@ _weekday:
|
||||||
friday: "금요일"
|
friday: "금요일"
|
||||||
saturday: "토요일"
|
saturday: "토요일"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "프로필"
|
||||||
|
instanceInfo: "인스턴스 정보"
|
||||||
memo: "스티커 메모"
|
memo: "스티커 메모"
|
||||||
notifications: "알림"
|
notifications: "알림"
|
||||||
timeline: "타임라인"
|
timeline: "타임라인"
|
||||||
|
|
|
@ -440,6 +440,8 @@ _sfx:
|
||||||
notification: "Meldingen"
|
notification: "Meldingen"
|
||||||
chat: "Chat"
|
chat: "Chat"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profiel"
|
||||||
|
instanceInfo: "Serverinformatie"
|
||||||
notifications: "Meldingen"
|
notifications: "Meldingen"
|
||||||
timeline: "Tijdlijn"
|
timeline: "Tijdlijn"
|
||||||
activity: "Activiteit"
|
activity: "Activiteit"
|
||||||
|
|
|
@ -1213,6 +1213,8 @@ _weekday:
|
||||||
friday: "Piątek"
|
friday: "Piątek"
|
||||||
saturday: "Sobota"
|
saturday: "Sobota"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Informacje o instancji"
|
||||||
memo: "Przypięte notatki"
|
memo: "Przypięte notatki"
|
||||||
notifications: "Powiadomienia"
|
notifications: "Powiadomienia"
|
||||||
timeline: "Oś czasu"
|
timeline: "Oś czasu"
|
||||||
|
|
|
@ -488,6 +488,8 @@ _sfx:
|
||||||
notification: "Notificações"
|
notification: "Notificações"
|
||||||
chat: "Chat"
|
chat: "Chat"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Perfil"
|
||||||
|
instanceInfo: "Informações da instância"
|
||||||
notifications: "Notificações"
|
notifications: "Notificações"
|
||||||
timeline: "Timeline"
|
timeline: "Timeline"
|
||||||
activity: "atividade"
|
activity: "atividade"
|
||||||
|
|
|
@ -667,6 +667,8 @@ _sfx:
|
||||||
notification: "Notificări"
|
notification: "Notificări"
|
||||||
chat: "Chat"
|
chat: "Chat"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Informații despre instanță"
|
||||||
notifications: "Notificări"
|
notifications: "Notificări"
|
||||||
timeline: "Cronologie"
|
timeline: "Cronologie"
|
||||||
activity: "Activitate"
|
activity: "Activitate"
|
||||||
|
|
|
@ -1213,6 +1213,8 @@ _weekday:
|
||||||
friday: "Пятница"
|
friday: "Пятница"
|
||||||
saturday: "Суббота"
|
saturday: "Суббота"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Профиль"
|
||||||
|
instanceInfo: "Информация об инстансе"
|
||||||
memo: "Напоминания"
|
memo: "Напоминания"
|
||||||
notifications: "Уведомления"
|
notifications: "Уведомления"
|
||||||
timeline: "Лента"
|
timeline: "Лента"
|
||||||
|
|
|
@ -1295,6 +1295,8 @@ _weekday:
|
||||||
friday: "Piatok"
|
friday: "Piatok"
|
||||||
saturday: "Sobota"
|
saturday: "Sobota"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Informácie o serveri"
|
||||||
memo: "Prilepené poznámky"
|
memo: "Prilepené poznámky"
|
||||||
notifications: "Oznámenia"
|
notifications: "Oznámenia"
|
||||||
timeline: "Časová os"
|
timeline: "Časová os"
|
||||||
|
|
|
@ -327,7 +327,16 @@ pinnedNotes: "Fästad not"
|
||||||
enableHcaptcha: "Aktivera hCaptcha"
|
enableHcaptcha: "Aktivera hCaptcha"
|
||||||
enableRecaptcha: "Aktivera reCAPTCHA"
|
enableRecaptcha: "Aktivera reCAPTCHA"
|
||||||
enableTurnstile: "Aktivera Turnstile"
|
enableTurnstile: "Aktivera Turnstile"
|
||||||
|
antennas: "Antenner"
|
||||||
|
manageAntennas: "Hantera Antenner"
|
||||||
|
antennaSource: "Antennkälla"
|
||||||
|
antennaKeywords: "Nyckelord att lyssna efter"
|
||||||
|
antennaExcludeKeywords: "Nyckelord att exkludera"
|
||||||
|
antennaKeywordsDescription: "Separera med mellanslag för en AND kondition, eller med nya linjer för en OR kondition"
|
||||||
|
notifyAntenna: "Notifiera om nya noter"
|
||||||
|
withFileAntenna: "Endast noter med filer"
|
||||||
enableServiceworker: "Aktivera pushnotiser i denna webbläsaren"
|
enableServiceworker: "Aktivera pushnotiser i denna webbläsaren"
|
||||||
|
antennaUsersDescription: "Ange ett användarnamn per linje"
|
||||||
recentlyUpdatedUsers: "Nyligen aktiva användare"
|
recentlyUpdatedUsers: "Nyligen aktiva användare"
|
||||||
recentlyRegisteredUsers: "Nyligen registrerade användare"
|
recentlyRegisteredUsers: "Nyligen registrerade användare"
|
||||||
userList: "Listor"
|
userList: "Listor"
|
||||||
|
@ -377,7 +386,16 @@ _sfx:
|
||||||
note: "Noter"
|
note: "Noter"
|
||||||
notification: "Notifikationer"
|
notification: "Notifikationer"
|
||||||
chat: "Chatt"
|
chat: "Chatt"
|
||||||
|
antenna: "Antenner"
|
||||||
|
_antennaSources:
|
||||||
|
all: "Alla noter"
|
||||||
|
homeTimeline: "Noter från följda användare"
|
||||||
|
users: "Noter från specifika användare"
|
||||||
|
userList: "Noter från en specificerad lista av användare"
|
||||||
|
userGroup: "Noter från användare i en specificerad grupp"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
|
instanceInfo: "Instansinformation"
|
||||||
notifications: "Notifikationer"
|
notifications: "Notifikationer"
|
||||||
timeline: "Tidslinje"
|
timeline: "Tidslinje"
|
||||||
activity: "Aktivitet"
|
activity: "Aktivitet"
|
||||||
|
@ -395,6 +413,7 @@ _profile:
|
||||||
changeAvatar: "Ändra profilbild"
|
changeAvatar: "Ändra profilbild"
|
||||||
changeBanner: "Ändra banner"
|
changeBanner: "Ändra banner"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
|
allNotes: "Alla noter"
|
||||||
followingList: "Följer"
|
followingList: "Följer"
|
||||||
muteList: "Tysta"
|
muteList: "Tysta"
|
||||||
blockingList: "Blockera"
|
blockingList: "Blockera"
|
||||||
|
@ -423,5 +442,6 @@ _deck:
|
||||||
_columns:
|
_columns:
|
||||||
notifications: "Notifikationer"
|
notifications: "Notifikationer"
|
||||||
tl: "Tidslinje"
|
tl: "Tidslinje"
|
||||||
|
antenna: "Antenner"
|
||||||
list: "Listor"
|
list: "Listor"
|
||||||
mentions: "Omnämningar"
|
mentions: "Omnämningar"
|
||||||
|
|
|
@ -1302,6 +1302,8 @@ _weekday:
|
||||||
friday: "วันศุกร์"
|
friday: "วันศุกร์"
|
||||||
saturday: "วันเสาร์"
|
saturday: "วันเสาร์"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "โปรไฟล์"
|
||||||
|
instanceInfo: "ข้อมูล อินสแตนซ์"
|
||||||
memo: "โน้ตแปะ"
|
memo: "โน้ตแปะ"
|
||||||
notifications: "การเเจ้งเตือน"
|
notifications: "การเเจ้งเตือน"
|
||||||
timeline: "ไทม์ไลน์"
|
timeline: "ไทม์ไลน์"
|
||||||
|
|
|
@ -53,6 +53,7 @@ _mfm:
|
||||||
_sfx:
|
_sfx:
|
||||||
notification: "Bildirim"
|
notification: "Bildirim"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Profil"
|
||||||
notifications: "Bildirim"
|
notifications: "Bildirim"
|
||||||
timeline: "Zaman çizelgesi"
|
timeline: "Zaman çizelgesi"
|
||||||
_profile:
|
_profile:
|
||||||
|
|
|
@ -1229,6 +1229,8 @@ _weekday:
|
||||||
friday: "П'ятниця"
|
friday: "П'ятниця"
|
||||||
saturday: "Субота"
|
saturday: "Субота"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Профіль"
|
||||||
|
instanceInfo: "Про цей інстанс"
|
||||||
memo: "Нагадування"
|
memo: "Нагадування"
|
||||||
notifications: "Сповіщення"
|
notifications: "Сповіщення"
|
||||||
timeline: "Стрічка"
|
timeline: "Стрічка"
|
||||||
|
|
|
@ -1271,6 +1271,8 @@ _weekday:
|
||||||
friday: "Thứ Sáu"
|
friday: "Thứ Sáu"
|
||||||
saturday: "Thứ Bảy"
|
saturday: "Thứ Bảy"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "Trang cá nhân"
|
||||||
|
instanceInfo: "Thông tin máy chủ"
|
||||||
memo: "Tút đã ghim"
|
memo: "Tút đã ghim"
|
||||||
notifications: "Thông báo"
|
notifications: "Thông báo"
|
||||||
timeline: "Bảng tin"
|
timeline: "Bảng tin"
|
||||||
|
|
|
@ -922,7 +922,8 @@ numberOfLikes: "点赞数"
|
||||||
show: "显示"
|
show: "显示"
|
||||||
neverShow: "不再显示"
|
neverShow: "不再显示"
|
||||||
remindMeLater: "稍后提醒我"
|
remindMeLater: "稍后提醒我"
|
||||||
didYouLikeMisskey: "你在Misskey玩得还开心吗?"
|
didYouLikeMisskey: "您喜欢Misskey吗?"
|
||||||
|
pleaseDonate: "Misskey是{host}所使用的免费软件。为了今后也能够维持Misskey的开发,请在有余力的情况下进行捐助!"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。"
|
description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。"
|
||||||
sensitivity: "检测敏感度"
|
sensitivity: "检测敏感度"
|
||||||
|
@ -1301,6 +1302,8 @@ _weekday:
|
||||||
friday: "星期五"
|
friday: "星期五"
|
||||||
saturday: "星期六"
|
saturday: "星期六"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "个人资料"
|
||||||
|
instanceInfo: "实例信息"
|
||||||
memo: "便签"
|
memo: "便签"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
timeline: "时间线"
|
timeline: "时间线"
|
||||||
|
@ -1327,6 +1330,7 @@ _widgets:
|
||||||
userList: "用户列表"
|
userList: "用户列表"
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "选择列表"
|
chooseList: "选择列表"
|
||||||
|
clicker: "点击器"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隐藏"
|
hide: "隐藏"
|
||||||
show: "查看更多"
|
show: "查看更多"
|
||||||
|
|
|
@ -797,7 +797,7 @@ squareAvatars: "頭像以方形顯示"
|
||||||
sent: "發送"
|
sent: "發送"
|
||||||
received: "收取"
|
received: "收取"
|
||||||
searchResult: "搜尋結果"
|
searchResult: "搜尋結果"
|
||||||
hashtags: "#tag"
|
hashtags: "標籤"
|
||||||
troubleshooting: "故障排除"
|
troubleshooting: "故障排除"
|
||||||
useBlurEffect: "在 UI 上使用模糊效果"
|
useBlurEffect: "在 UI 上使用模糊效果"
|
||||||
learnMore: "更多資訊"
|
learnMore: "更多資訊"
|
||||||
|
@ -1159,7 +1159,7 @@ _theme:
|
||||||
navActive: "側邊欄文本 (活動)"
|
navActive: "側邊欄文本 (活動)"
|
||||||
navIndicator: "側邊欄指示符"
|
navIndicator: "側邊欄指示符"
|
||||||
link: "鏈接"
|
link: "鏈接"
|
||||||
hashtag: "#tag"
|
hashtag: "標籤"
|
||||||
mention: "提到"
|
mention: "提到"
|
||||||
mentionMe: "提到了我"
|
mentionMe: "提到了我"
|
||||||
renote: "轉發貼文"
|
renote: "轉發貼文"
|
||||||
|
@ -1302,6 +1302,8 @@ _weekday:
|
||||||
friday: "週五"
|
friday: "週五"
|
||||||
saturday: "週六"
|
saturday: "週六"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
profile: "個人檔案"
|
||||||
|
instanceInfo: "實例資訊"
|
||||||
memo: "備忘錄"
|
memo: "備忘錄"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
timeline: "時間軸"
|
timeline: "時間軸"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "13.0.0-beta.36",
|
"version": "13.0.0-beta.39",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export class PollChoiceLength1673336077243 {
|
||||||
|
name = 'PollChoiceLength1673336077243'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "poll" ALTER COLUMN "choices" TYPE character varying(256) array`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "poll" ALTER COLUMN "choices" TYPE character varying(128) array`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ export class Poll {
|
||||||
public multiple: boolean;
|
public multiple: boolean;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 128, array: true, default: '{}',
|
length: 256, array: true, default: '{}',
|
||||||
})
|
})
|
||||||
public choices: string[];
|
public choices: string[];
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||||
import { Cache } from '@/misc/cache.js';
|
import { Cache } from '@/misc/cache.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import NotesChart from '@/core/chart/charts/notes.js';
|
||||||
|
import UsersChart from '@/core/chart/charts/users.js';
|
||||||
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
||||||
|
|
||||||
const nodeinfo2_1path = '/nodeinfo/2.1';
|
const nodeinfo2_1path = '/nodeinfo/2.1';
|
||||||
|
@ -27,6 +29,8 @@ export class NodeinfoServerService {
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
|
private notesChart: NotesChart,
|
||||||
|
private usersChart: UsersChart,
|
||||||
) {
|
) {
|
||||||
//this.createServer = this.createServer.bind(this);
|
//this.createServer = this.createServer.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -46,20 +50,27 @@ export class NodeinfoServerService {
|
||||||
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||||
const nodeinfo2 = async () => {
|
const nodeinfo2 = async () => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
|
||||||
|
const notesChart = await this.notesChart.getChart('hour', 1, null);
|
||||||
|
const localPosts = notesChart.local.total[0];
|
||||||
|
|
||||||
|
const usersChart = await this.usersChart.getChart('hour', 1, null);
|
||||||
|
const total = usersChart.local.total[0];
|
||||||
|
|
||||||
const [
|
const [
|
||||||
meta,
|
meta,
|
||||||
total,
|
//activeHalfyear,
|
||||||
activeHalfyear,
|
//activeMonth,
|
||||||
activeMonth,
|
|
||||||
localPosts,
|
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
this.metaService.fetch(true),
|
this.metaService.fetch(true),
|
||||||
this.usersRepository.count({ where: { host: IsNull() } }),
|
// 重い
|
||||||
this.usersRepository.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 15552000000)) } }),
|
//this.usersRepository.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 15552000000)) } }),
|
||||||
this.usersRepository.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 2592000000)) } }),
|
//this.usersRepository.count({ where: { host: IsNull(), lastActiveDate: MoreThan(new Date(now - 2592000000)) } }),
|
||||||
this.notesRepository.count({ where: { userHost: IsNull() } }),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const activeHalfyear = null;
|
||||||
|
const activeMonth = null;
|
||||||
|
|
||||||
const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null;
|
const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -3,6 +3,8 @@ import { IsNull } from 'typeorm';
|
||||||
import type { InstancesRepository, NoteReactionsRepository, NotesRepository, UsersRepository } from '@/models/index.js';
|
import type { InstancesRepository, NoteReactionsRepository, NotesRepository, UsersRepository } from '@/models/index.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import NotesChart from '@/core/chart/charts/notes.js';
|
||||||
|
import UsersChart from '@/core/chart/charts/users.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: false,
|
requireCredential: false,
|
||||||
|
@ -66,21 +68,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
|
|
||||||
@Inject(DI.noteReactionsRepository)
|
@Inject(DI.noteReactionsRepository)
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
private noteReactionsRepository: NoteReactionsRepository,
|
||||||
|
|
||||||
|
private notesChart: NotesChart,
|
||||||
|
private usersChart: UsersChart,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async () => {
|
super(meta, paramDef, async () => {
|
||||||
|
const notesChart = await this.notesChart.getChart('hour', 1, null);
|
||||||
|
const notesCount = notesChart.local.total[0] + notesChart.remote.total[0];
|
||||||
|
const originalNotesCount = notesChart.local.total[0];
|
||||||
|
|
||||||
|
const usersChart = await this.usersChart.getChart('hour', 1, null);
|
||||||
|
const usersCount = usersChart.local.total[0] + usersChart.remote.total[0];
|
||||||
|
const originalUsersCount = usersChart.local.total[0];
|
||||||
|
|
||||||
const [
|
const [
|
||||||
notesCount,
|
|
||||||
originalNotesCount,
|
|
||||||
usersCount,
|
|
||||||
originalUsersCount,
|
|
||||||
reactionsCount,
|
reactionsCount,
|
||||||
//originalReactionsCount,
|
//originalReactionsCount,
|
||||||
instances,
|
instances,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
this.notesRepository.count({ cache: 3600000 }), // 1 hour
|
|
||||||
this.notesRepository.count({ where: { userHost: IsNull() }, cache: 3600000 }),
|
|
||||||
this.usersRepository.count({ cache: 3600000 }),
|
|
||||||
this.usersRepository.count({ where: { host: IsNull() }, cache: 3600000 }),
|
|
||||||
this.noteReactionsRepository.count({ cache: 3600000 }), // 1 hour
|
this.noteReactionsRepository.count({ cache: 3600000 }), // 1 hour
|
||||||
//this.noteReactionsRepository.count({ where: { userHost: IsNull() }, cache: 3600000 }),
|
//this.noteReactionsRepository.count({ where: { userHost: IsNull() }, cache: 3600000 }),
|
||||||
this.instancesRepository.count({ cache: 3600000 }),
|
this.instancesRepository.count({ cache: 3600000 }),
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
"insert-text-at-cursor": "0.3.0",
|
"insert-text-at-cursor": "0.3.0",
|
||||||
"is-file-animated": "1.0.2",
|
"is-file-animated": "1.0.2",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"katex": "0.16.4",
|
|
||||||
"matter-js": "0.18.0",
|
"matter-js": "0.18.0",
|
||||||
"mfm-js": "0.23.1",
|
"mfm-js": "0.23.1",
|
||||||
"misskey-js": "0.0.14",
|
"misskey-js": "0.0.14",
|
||||||
|
@ -73,7 +72,6 @@
|
||||||
"@types/glob": "8.0.0",
|
"@types/glob": "8.0.0",
|
||||||
"@types/gulp": "4.0.10",
|
"@types/gulp": "4.0.10",
|
||||||
"@types/gulp-rename": "2.0.1",
|
"@types/gulp-rename": "2.0.1",
|
||||||
"@types/katex": "0.16.0",
|
|
||||||
"@types/matter-js": "0.18.2",
|
"@types/matter-js": "0.18.2",
|
||||||
"@types/punycode": "2.1.0",
|
"@types/punycode": "2.1.0",
|
||||||
"@types/sanitize-html": "^2.8.0",
|
"@types/sanitize-html": "^2.8.0",
|
||||||
|
|
|
@ -80,7 +80,6 @@ export default defineComponent({
|
||||||
} else {
|
} else {
|
||||||
if (props.ad && item._shouldInsertAd_) {
|
if (props.ad && item._shouldInsertAd_) {
|
||||||
return [h(MkAd, {
|
return [h(MkAd, {
|
||||||
class: 'a', // advertiseの意(ブロッカー対策)
|
|
||||||
key: item.id + ':ad',
|
key: item.id + ':ad',
|
||||||
prefer: ['horizontal', 'horizontal-big'],
|
prefer: ['horizontal', 'horizontal-big'],
|
||||||
}), el];
|
}), el];
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :prefer-type="'dialog'" :z-priority="'high'" @click="done(true)" @closed="emit('closed')">
|
<MkModal ref="modal" :prefer-type="'dialog'" :z-priority="'high'" @click="done(true)" @closed="emit('closed')">
|
||||||
<div class="mk-dialog">
|
<div :class="$style.root">
|
||||||
<div v-if="icon" class="icon">
|
<div v-if="icon" :class="$style.icon">
|
||||||
<i :class="icon"></i>
|
<i :class="icon"></i>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="!input && !select" class="icon" :class="type">
|
<div v-else-if="!input && !select" :class="[$style.icon, $style['type_' + type]]">
|
||||||
<i v-if="type === 'success'" class="ti ti-check"></i>
|
<i v-if="type === 'success'" :class="$style.iconInner" class="ti ti-check"></i>
|
||||||
<i v-else-if="type === 'error'" class="ti ti-circle-x"></i>
|
<i v-else-if="type === 'error'" :class="$style.iconInner" class="ti ti-circle-x"></i>
|
||||||
<i v-else-if="type === 'warning'" class="ti ti-alert-triangle"></i>
|
<i v-else-if="type === 'warning'" :class="$style.iconInner" class="ti ti-alert-triangle"></i>
|
||||||
<i v-else-if="type === 'info'" class="ti ti-info-circle"></i>
|
<i v-else-if="type === 'info'" :class="$style.iconInner" class="ti ti-info-circle"></i>
|
||||||
<i v-else-if="type === 'question'" class="ti ti-question-circle"></i>
|
<i v-else-if="type === 'question'" :class="$style.iconInner" class="ti ti-question-circle"></i>
|
||||||
<MkLoading v-else-if="type === 'waiting'" :em="true"/>
|
<MkLoading v-else-if="type === 'waiting'" :class="$style.iconInner" :em="true"/>
|
||||||
</div>
|
</div>
|
||||||
<header v-if="title"><Mfm :text="title"/></header>
|
<header v-if="title" :class="$style.title"><Mfm :text="title"/></header>
|
||||||
<div v-if="text" class="body"><Mfm :text="text"/></div>
|
<div v-if="text" :class="$style.text"><Mfm :text="text"/></div>
|
||||||
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" @keydown="onInputKeydown">
|
<MkInput v-if="input" v-model="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder || undefined" @keydown="onInputKeydown">
|
||||||
<template v-if="input.type === 'password'" #prefix><i class="ti ti-lock"></i></template>
|
<template v-if="input.type === 'password'" #prefix><i class="ti ti-lock"></i></template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
@ -27,11 +27,11 @@
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</template>
|
</template>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
<div v-if="(showOkButton || showCancelButton) && !actions" class="buttons">
|
<div v-if="(showOkButton || showCancelButton) && !actions" :class="$style.buttons">
|
||||||
<MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ (showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt }}</MkButton>
|
<MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ (showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt }}</MkButton>
|
||||||
<MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
|
<MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="actions" class="buttons">
|
<div v-if="actions" :class="$style.buttons">
|
||||||
<MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); close(); }">{{ action.text }}</MkButton>
|
<MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); close(); }">{{ action.text }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -143,8 +143,8 @@ onBeforeUnmount(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.mk-dialog {
|
.root {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
|
@ -153,56 +153,56 @@ onBeforeUnmount(() => {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
> .icon {
|
.icon {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
|
|
||||||
&.info {
|
& + .title {
|
||||||
color: #55c4dd;
|
margin-top: 8px;
|
||||||
}
|
|
||||||
|
|
||||||
&.success {
|
|
||||||
color: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.error {
|
|
||||||
color: var(--error);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.warning {
|
|
||||||
color: var(--warn);
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
& + header {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> header {
|
|
||||||
margin: 0 0 8px 0;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.1em;
|
|
||||||
|
|
||||||
& + .body {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .body {
|
|
||||||
margin: 16px 0 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .buttons {
|
|
||||||
margin-top: 16px;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
margin: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.iconInner {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type_info {
|
||||||
|
color: #55c4dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type_success {
|
||||||
|
color: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.type_error {
|
||||||
|
color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.type_warning {
|
||||||
|
color: var(--warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.1em;
|
||||||
|
|
||||||
|
& + .text {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin: 16px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
<template>
|
|
||||||
<XFormula :formula="formula" :block="block"/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, defineAsyncComponent } from 'vue';
|
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
XFormula: defineAsyncComponent(() => import('@/components/MkFormulaCore.vue')),
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
formula: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
block: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,34 +0,0 @@
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
|
||||||
<template>
|
|
||||||
<div v-if="block" v-html="compiledFormula"></div>
|
|
||||||
<span v-else v-html="compiledFormula"></span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import katex from 'katex';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
props: {
|
|
||||||
formula: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
block: {
|
|
||||||
type: Boolean,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
compiledFormula(): any {
|
|
||||||
return katex.renderToString(this.formula, {
|
|
||||||
throwOnError: false,
|
|
||||||
} as any);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
@import "../../node_modules/katex/dist/katex.min.css";
|
|
||||||
</style>
|
|
|
@ -75,7 +75,7 @@ function close() {
|
||||||
|
|
||||||
&.asDrawer {
|
&.asDrawer {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 16px 16px calc(env(safe-area-inset-bottom, 0px) + 16px) 16px;
|
padding: 16px 16px max(env(safe-area-inset-bottom, 0px), 16px) 16px;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<component
|
<component
|
||||||
:is="self ? 'MkA' : 'a'" ref="el" class="xlcxczvw _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
:is="self ? 'MkA' : 'a'" ref="el" style="word-break: break-all;" class="_link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
||||||
:title="url"
|
:title="url"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<i v-if="target === '_blank'" class="ti ti-external-link icon"></i>
|
<i v-if="target === '_blank'" class="ti ti-external-link" :class="$style.icon"></i>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -35,13 +35,9 @@ useTooltip($$(el), (showing) => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.xlcxczvw {
|
.icon {
|
||||||
word-break: break-all;
|
padding-left: 2px;
|
||||||
|
font-size: .9em;
|
||||||
> .icon {
|
|
||||||
padding-left: 2px;
|
|
||||||
font-size: .9em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,54 +2,54 @@
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
ref="itemsEl" v-hotkey="keymap"
|
ref="itemsEl" v-hotkey="keymap"
|
||||||
class="rrevdjwt _popup _shadow"
|
class="_popup _shadow"
|
||||||
:class="{ center: align === 'center', asDrawer }"
|
:class="[$style.root, { [$style.center]: align === 'center', [$style.asDrawer]: asDrawer }]"
|
||||||
:style="{ width: (width && !asDrawer) ? width + 'px' : '', maxHeight: maxHeight ? maxHeight + 'px' : '' }"
|
:style="{ width: (width && !asDrawer) ? width + 'px' : '', maxHeight: maxHeight ? maxHeight + 'px' : '' }"
|
||||||
@contextmenu.self="e => e.preventDefault()"
|
@contextmenu.self="e => e.preventDefault()"
|
||||||
>
|
>
|
||||||
<template v-for="(item, i) in items2">
|
<template v-for="(item, i) in items2">
|
||||||
<div v-if="item === null" class="divider"></div>
|
<div v-if="item === null" :class="$style.divider"></div>
|
||||||
<span v-else-if="item.type === 'label'" class="label item">
|
<span v-else-if="item.type === 'label'" :class="[$style.label, $style.item]">
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="item.type === 'pending'" :tabindex="i" class="pending item">
|
<span v-else-if="item.type === 'pending'" :tabindex="i" :class="[$style.pending, $style.item]">
|
||||||
<span><MkEllipsis/></span>
|
<span><MkEllipsis/></span>
|
||||||
</span>
|
</span>
|
||||||
<MkA v-else-if="item.type === 'link'" :to="item.to" :tabindex="i" class="_button item" @click.passive="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
<MkA v-else-if="item.type === 'link'" :to="item.to" :tabindex="i" class="_button" :class="$style.item" @click.passive="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||||
<i v-if="item.icon" class="ti-fw" :class="item.icon"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
|
||||||
</MkA>
|
</MkA>
|
||||||
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" :tabindex="i" class="_button item" @click="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" :tabindex="i" class="_button" :class="$style.item" @click="close(true)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||||
<i v-if="item.icon" class="ti-fw" :class="item.icon"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
|
||||||
</a>
|
</a>
|
||||||
<button v-else-if="item.type === 'user'" :tabindex="i" class="_button item" :class="{ active: item.active }" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
<button v-else-if="item.type === 'user'" :tabindex="i" class="_button" :class="[$style.item, { [$style.active]: item.active }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||||
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
|
<MkAvatar :user="item.user" :class="$style.avatar"/><MkUserName :user="item.user"/>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<span v-else-if="item.type === 'switch'" :tabindex="i" class="item" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
<span v-else-if="item.type === 'switch'" :tabindex="i" :class="$style.item" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||||
<MkSwitch v-model="item.ref" :disabled="item.disabled" class="form-switch">{{ item.text }}</MkSwitch>
|
<MkSwitch v-model="item.ref" :disabled="item.disabled" class="form-switch">{{ item.text }}</MkSwitch>
|
||||||
</span>
|
</span>
|
||||||
<button v-else-if="item.type === 'parent'" :tabindex="i" class="_button item parent" :class="{ childShowing: childShowingItem === item }" @mouseenter="showChildren(item, $event)">
|
<button v-else-if="item.type === 'parent'" :tabindex="i" class="_button" :class="[$style.item, $style.parent, { [$style.childShowing]: childShowingItem === item }]" @mouseenter="showChildren(item, $event)">
|
||||||
<i v-if="item.icon" class="ti-fw" :class="item.icon"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<span class="caret"><i class="ti ti-caret-right ti-fw"></i></span>
|
<span :class="$style.caret"><i class="ti ti-caret-right ti-fw"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<button v-else :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
<button v-else :tabindex="i" class="_button" :class="[$style.item, { [$style.danger]: item.danger, [$style.active]: item.active }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||||
<i v-if="item.icon" class="ti-fw" :class="item.icon"></i>
|
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
|
||||||
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" :class="$style.indicator"><i class="_indicatorCircle"></i></span>
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
<span v-if="items2.length === 0" class="none item">
|
<span v-if="items2.length === 0" :class="[$style.none, $style.item]">
|
||||||
<span>{{ i18n.ts.none }}</span>
|
<span>{{ i18n.ts.none }}</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="childMenu" class="child">
|
<div v-if="childMenu" :class="$style.child">
|
||||||
<XChild ref="child" :items="childMenu" :target-element="childTarget" :root-element="itemsEl" showing @actioned="childActioned"/>
|
<XChild ref="child" :items="childMenu" :target-element="childTarget" :root-element="itemsEl" showing @actioned="childActioned"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -186,8 +186,8 @@ onBeforeUnmount(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.rrevdjwt {
|
.root {
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
|
@ -200,143 +200,8 @@ onBeforeUnmount(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .item {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
padding: 5px 16px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-size: 0.9em;
|
|
||||||
line-height: 20px;
|
|
||||||
text-align: left;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
z-index: -1;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: auto;
|
|
||||||
width: calc(100% - 16px);
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:disabled):hover {
|
|
||||||
color: var(--accent);
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: var(--accentedBg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.danger {
|
|
||||||
color: #ff2a2a;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: #ff4242;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: #d42e2e !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&.active {
|
|
||||||
color: var(--fgOnAccent) !important;
|
|
||||||
opacity: 1;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: var(--accent) !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:active):focus-visible {
|
|
||||||
box-shadow: 0 0 0 2px var(--focus) inset;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.label {
|
|
||||||
pointer-events: none;
|
|
||||||
font-size: 0.7em;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.pending {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.none {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.parent {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
> .caret {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.childShowing {
|
|
||||||
color: var(--accent);
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: var(--accentedBg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> i {
|
|
||||||
margin-right: 5px;
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .avatar {
|
|
||||||
margin-right: 5px;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .indicator {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
left: 13px;
|
|
||||||
color: var(--indicator);
|
|
||||||
font-size: 12px;
|
|
||||||
animation: blink 1s infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .divider {
|
|
||||||
margin: 8px 0;
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.asDrawer {
|
&.asDrawer {
|
||||||
padding: 12px 0 calc(env(safe-area-inset-bottom, 0px) + 12px) 0;
|
padding: 12px 0 max(env(safe-area-inset-bottom, 0px), 12px) 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
|
@ -351,7 +216,7 @@ onBeforeUnmount(() => {
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> i {
|
> .icon {
|
||||||
margin-right: 14px;
|
margin-right: 14px;
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
|
@ -362,4 +227,139 @@ onBeforeUnmount(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
padding: 5px 16px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 0.9em;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
width: calc(100% - 16px);
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: var(--accentedBg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
color: #ff2a2a;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: #ff4242;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: #d42e2e !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&.active {
|
||||||
|
color: var(--fgOnAccent) !important;
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: var(--accent) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:active):focus-visible {
|
||||||
|
box-shadow: 0 0 0 2px var(--focus) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.label {
|
||||||
|
pointer-events: none;
|
||||||
|
font-size: 0.7em;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.pending {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.none {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.parent {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
|
&.childShowing {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: var(--accentedBg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caret {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
left: 13px;
|
||||||
|
color: var(--indicator);
|
||||||
|
font-size: 12px;
|
||||||
|
animation: blink 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
margin: 8px 0;
|
||||||
|
border-top: solid 0.5px var(--divider);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -4,27 +4,26 @@
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="el"
|
ref="el"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
class="tkcbzcuz"
|
:class="$style.root"
|
||||||
:tabindex="!isDeleted ? '-1' : null"
|
:tabindex="!isDeleted ? '-1' : null"
|
||||||
:class="{ renote: isRenote }"
|
|
||||||
>
|
>
|
||||||
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/>
|
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||||
<div v-if="pinned" class="info"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
|
<div v-if="pinned" :class="$style.tip"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
|
||||||
<div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>
|
<!--<div v-if="appearNote._prId_" class="tip"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>-->
|
||||||
<div v-if="appearNote._featuredId_" class="info"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>
|
<!--<div v-if="appearNote._featuredId_" class="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>-->
|
||||||
<div v-if="isRenote" class="renote">
|
<div v-if="isRenote" :class="$style.renote">
|
||||||
<MkAvatar v-once class="avatar" :user="note.user"/>
|
<MkAvatar v-once :class="$style.renoteAvatar" :user="note.user"/>
|
||||||
<i class="ti ti-repeat"></i>
|
<i class="ti ti-repeat" style="margin-right: 4px;"></i>
|
||||||
<I18n :src="i18n.ts.renotedBy" tag="span">
|
<I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText">
|
||||||
<template #user>
|
<template #user>
|
||||||
<MkA v-user-preview="note.userId" class="name" :to="userPage(note.user)">
|
<MkA v-user-preview="note.userId" :class="$style.renoteUserName" :to="userPage(note.user)">
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
<div class="info">
|
<div :class="$style.renoteInfo">
|
||||||
<button ref="renoteTime" class="_button time" @click="showRenoteMenu()">
|
<button ref="renoteTime" :class="$style.renoteTime" class="_button" @click="showRenoteMenu()">
|
||||||
<i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i>
|
<i v-if="isMyRenote" class="ti ti-dots" :class="$style.renoteMenu"></i>
|
||||||
<MkTime :time="note.createdAt"/>
|
<MkTime :time="note.createdAt"/>
|
||||||
</button>
|
</button>
|
||||||
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
|
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
|
||||||
|
@ -35,80 +34,80 @@
|
||||||
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
|
<span v-if="note.localOnly" style="margin-left: 0.5em;" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<article class="article" @contextmenu.stop="onContextmenu">
|
<article :class="$style.article" @contextmenu.stop="onContextmenu">
|
||||||
<MkAvatar v-once class="avatar" :user="appearNote.user"/>
|
<MkAvatar v-once :class="$style.avatar" :user="appearNote.user"/>
|
||||||
<div class="main">
|
<div :class="$style.main">
|
||||||
<MkNoteHeader class="header" :note="appearNote" :mini="true"/>
|
<MkNoteHeader :class="$style.header" :note="appearNote" :mini="true"/>
|
||||||
<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
|
<MkInstanceTicker v-if="showTicker" :class="$style.ticker" :instance="appearNote.user.instance"/>
|
||||||
<div class="body">
|
<div style="container-type: inline-size;">
|
||||||
<p v-if="appearNote.cw != null" class="cw">
|
<p v-if="appearNote.cw != null" :class="$style.cw">
|
||||||
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i"/>
|
<Mfm v-if="appearNote.cw != ''" style="margin-right: 8px;" :text="appearNote.cw" :author="appearNote.user" :i="$i"/>
|
||||||
<MkCwButton v-model="showContent" :note="appearNote"/>
|
<MkCwButton v-model="showContent" :note="appearNote"/>
|
||||||
</p>
|
</p>
|
||||||
<div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed, isLong }">
|
<div v-show="appearNote.cw == null || showContent" :class="[{ [$style.contentCollapsed]: collapsed }]">
|
||||||
<div class="text">
|
<div :class="$style.text">
|
||||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
||||||
<MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
<MkA v-if="appearNote.replyId" :class="$style.replyIcon" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
||||||
<Mfm v-if="appearNote.text" v-once :text="appearNote.text" :author="appearNote.user" :i="$i"/>
|
<Mfm v-if="appearNote.text" v-once :text="appearNote.text" :author="appearNote.user" :i="$i"/>
|
||||||
<a v-if="appearNote.renote != null" class="rp">RN:</a>
|
<div v-if="translating || translation" :class="$style.translation">
|
||||||
<div v-if="translating || translation" class="translation">
|
|
||||||
<MkLoading v-if="translating" mini/>
|
<MkLoading v-if="translating" mini/>
|
||||||
<div v-else class="translated">
|
<div v-else :class="$style.translated">
|
||||||
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
<b>{{ $t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
||||||
<Mfm :text="translation.text" :author="appearNote.user" :i="$i"/>
|
<Mfm :text="translation.text" :author="appearNote.user" :i="$i"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="appearNote.files.length > 0" class="files">
|
<div v-if="appearNote.files.length > 0" :class="$style.files">
|
||||||
<MkMediaList :media-list="appearNote.files"/>
|
<MkMediaList :media-list="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" class="poll"/>
|
<MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" :class="$style.poll"/>
|
||||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" class="url-preview"/>
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
|
||||||
<div v-if="appearNote.renote" class="renote"><MkNoteSimple :note="appearNote.renote" class="note"/></div>
|
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
||||||
<button v-if="isLong && collapsed" class="fade _button" @click="collapsed = false">
|
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
|
||||||
<span>{{ i18n.ts.showMore }}</span>
|
<span :class="$style.collapsedLabel">{{ i18n.ts.showMore }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button v-else-if="isLong && !collapsed" class="showLess _button" @click="collapsed = true">
|
<button v-else-if="isLong && !collapsed" :class="$style.showLess" class="_button" @click="collapsed = true">
|
||||||
<span>{{ i18n.ts.showLess }}</span>
|
<span :class="$style.showLessLabel">{{ i18n.ts.showLess }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
||||||
</div>
|
</div>
|
||||||
<footer class="footer">
|
<footer :class="$style.footer">
|
||||||
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
|
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
|
||||||
<button class="button _button" @click="reply()">
|
<button :class="$style.footerButton" class="_button" @click="reply()">
|
||||||
<i class="ti ti-arrow-back-up"></i>
|
<i class="ti ti-arrow-back-up"></i>
|
||||||
<p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p>
|
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canRenote"
|
v-if="canRenote"
|
||||||
ref="renoteButton"
|
ref="renoteButton"
|
||||||
class="button _button"
|
:class="$style.footerButton"
|
||||||
|
class="_button"
|
||||||
@mousedown="renote()"
|
@mousedown="renote()"
|
||||||
>
|
>
|
||||||
<i class="ti ti-repeat"></i>
|
<i class="ti ti-repeat"></i>
|
||||||
<p v-if="appearNote.renoteCount > 0" class="count">{{ appearNote.renoteCount }}</p>
|
<p v-if="appearNote.renoteCount > 0" :class="$style.footerButtonCount">{{ appearNote.renoteCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button v-else class="button _button" disabled>
|
<button v-else :class="$style.footerButton" class="_button" disabled>
|
||||||
<i class="ti ti-ban"></i>
|
<i class="ti ti-ban"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()">
|
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
|
||||||
<i class="ti ti-plus"></i>
|
<i class="ti ti-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
<button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
|
||||||
<i class="ti ti-minus"></i>
|
<i class="ti ti-minus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button ref="menuButton" class="button _button" @mousedown="menu()">
|
<button ref="menuButton" :class="$style.footerButton" class="_button" @mousedown="menu()">
|
||||||
<i class="ti ti-dots"></i>
|
<i class="ti ti-dots"></i>
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="muted" @click="muted = false">
|
<div v-else :class="$style.muted" @click="muted = false">
|
||||||
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
||||||
<template #name>
|
<template #name>
|
||||||
<MkA v-user-preview="appearNote.userId" class="name" :to="userPage(appearNote.user)">
|
<MkA v-user-preview="appearNote.userId" :to="userPage(appearNote.user)">
|
||||||
<MkUserName :user="appearNote.user"/>
|
<MkUserName :user="appearNote.user"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
|
@ -349,8 +348,8 @@ function readPromo() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.tkcbzcuz {
|
.root {
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: box-shadow 0.1s ease;
|
transition: box-shadow 0.1s ease;
|
||||||
font-size: 1.05em;
|
font-size: 1.05em;
|
||||||
|
@ -387,322 +386,259 @@ function readPromo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover > .article > .main > .footer > .button {
|
&:hover > .article > .main > .footer > .footerButton {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 16px 32px 8px 32px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-size: 90%;
|
|
||||||
white-space: pre;
|
|
||||||
color: #d28a3f;
|
|
||||||
|
|
||||||
> i {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .hide {
|
|
||||||
margin-left: auto;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .info + .article {
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .reply-to {
|
|
||||||
opacity: 0.7;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .renote {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 16px 32px 8px 32px;
|
|
||||||
line-height: 28px;
|
|
||||||
white-space: pre;
|
|
||||||
color: var(--renote);
|
|
||||||
|
|
||||||
> .avatar {
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: inline-block;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
margin: 0 8px 0 0;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> i {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> span {
|
|
||||||
overflow: hidden;
|
|
||||||
flex-shrink: 1;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
> .name {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .info {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
> .time {
|
|
||||||
flex-shrink: 0;
|
|
||||||
color: inherit;
|
|
||||||
|
|
||||||
> .dropdownIcon {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .renote + .article {
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .article {
|
|
||||||
display: flex;
|
|
||||||
padding: 28px 32px 18px;
|
|
||||||
|
|
||||||
> .avatar {
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: block;
|
|
||||||
margin: 0 14px 8px 0;
|
|
||||||
width: 58px;
|
|
||||||
height: 58px;
|
|
||||||
position: sticky;
|
|
||||||
top: calc(22px + var(--stickyTop, 0px));
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .main {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
|
|
||||||
> .body {
|
|
||||||
container-type: inline-size;
|
|
||||||
|
|
||||||
> .cw {
|
|
||||||
cursor: default;
|
|
||||||
display: block;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
|
|
||||||
> .text {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .content {
|
|
||||||
&.isLong {
|
|
||||||
> .showLess {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 1em;
|
|
||||||
position: sticky;
|
|
||||||
bottom: 1em;
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: inline-block;
|
|
||||||
background: var(--popup);
|
|
||||||
padding: 6px 10px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
border-radius: 999px;
|
|
||||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.collapsed {
|
|
||||||
position: relative;
|
|
||||||
max-height: 9em;
|
|
||||||
overflow: clip;
|
|
||||||
|
|
||||||
> .fade {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 64px;
|
|
||||||
background: linear-gradient(0deg, var(--panel), var(--X15));
|
|
||||||
|
|
||||||
> span {
|
|
||||||
display: inline-block;
|
|
||||||
background: var(--panel);
|
|
||||||
padding: 6px 10px;
|
|
||||||
font-size: 0.8em;
|
|
||||||
border-radius: 999px;
|
|
||||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
> span {
|
|
||||||
background: var(--panelHighlight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .text {
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
|
|
||||||
> .reply {
|
|
||||||
color: var(--accent);
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .rp {
|
|
||||||
margin-left: 4px;
|
|
||||||
font-style: oblique;
|
|
||||||
color: var(--renote);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .translation {
|
|
||||||
border: solid 0.5px var(--divider);
|
|
||||||
border-radius: var(--radius);
|
|
||||||
padding: 12px;
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .url-preview {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .poll {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .renote {
|
|
||||||
padding: 8px 0;
|
|
||||||
|
|
||||||
> .note {
|
|
||||||
padding: 16px;
|
|
||||||
border: dashed 1px var(--renote);
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .channel {
|
|
||||||
opacity: 0.7;
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .footer {
|
|
||||||
> .button {
|
|
||||||
margin: 0;
|
|
||||||
padding: 8px;
|
|
||||||
opacity: 0.7;
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--fgHighlighted);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .count {
|
|
||||||
display: inline;
|
|
||||||
margin: 0 0 0 8px;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.reacted {
|
|
||||||
color: var(--accent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .reply {
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: 500px) {
|
.tip {
|
||||||
.tkcbzcuz {
|
display: flex;
|
||||||
font-size: 0.9em;
|
align-items: center;
|
||||||
|
padding: 16px 32px 8px 32px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 90%;
|
||||||
|
white-space: pre;
|
||||||
|
color: #d28a3f;
|
||||||
|
}
|
||||||
|
|
||||||
> .article {
|
.tip + .article {
|
||||||
> .avatar {
|
padding-top: 8px;
|
||||||
width: 50px;
|
}
|
||||||
height: 50px;
|
|
||||||
}
|
.replyTo {
|
||||||
}
|
opacity: 0.7;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renote {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 32px 8px 32px;
|
||||||
|
line-height: 28px;
|
||||||
|
white-space: pre;
|
||||||
|
color: var(--renote);
|
||||||
|
|
||||||
|
& + .article {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.renoteAvatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin: 0 8px 0 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renoteText {
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 1;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renoteUserName {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renoteInfo {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renoteTime {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.renoteMenu {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article {
|
||||||
|
display: flex;
|
||||||
|
padding: 28px 32px 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: block !important;
|
||||||
|
margin: 0 14px 8px 0;
|
||||||
|
width: 58px;
|
||||||
|
height: 58px;
|
||||||
|
position: sticky !important;
|
||||||
|
top: calc(22px + var(--stickyTop, 0px));
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cw {
|
||||||
|
cursor: default;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.showLess {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1em;
|
||||||
|
position: sticky;
|
||||||
|
bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.howLessLabel {
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--popup);
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
border-radius: 999px;
|
||||||
|
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contentCollapsed {
|
||||||
|
position: relative;
|
||||||
|
max-height: 9em;
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 64px;
|
||||||
|
background: linear-gradient(0deg, var(--panel), var(--X15));
|
||||||
|
|
||||||
|
&:hover > .collapsedLabel {
|
||||||
|
background: var(--panelHighlight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsedLabel {
|
||||||
|
display: inline-block;
|
||||||
|
background: var(--panel);
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 0.8em;
|
||||||
|
border-radius: 999px;
|
||||||
|
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.replyIcon {
|
||||||
|
color: var(--accent);
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.translation {
|
||||||
|
border: solid 0.5px var(--divider);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
padding: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.urlPreview {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quote {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quoteNote {
|
||||||
|
padding: 16px;
|
||||||
|
border: dashed 1px var(--renote);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel {
|
||||||
|
opacity: 0.7;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerButton {
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px;
|
||||||
|
opacity: 0.7;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--fgHighlighted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerButtonCount {
|
||||||
|
display: inline;
|
||||||
|
margin: 0 0 0 8px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (max-width: 500px) {
|
||||||
|
.root {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: 450px) {
|
@container (max-width: 450px) {
|
||||||
.tkcbzcuz {
|
.renote {
|
||||||
> .renote {
|
padding: 8px 16px 0 16px;
|
||||||
padding: 8px 16px 0 16px;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
> .info {
|
.tip {
|
||||||
padding: 8px 16px 0 16px;
|
padding: 8px 16px 0 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .article {
|
.article {
|
||||||
padding: 14px 16px 9px;
|
padding: 14px 16px 9px;
|
||||||
|
}
|
||||||
|
|
||||||
> .avatar {
|
.avatar {
|
||||||
margin: 0 10px 8px 0;
|
margin: 0 10px 8px 0;
|
||||||
width: 46px;
|
width: 46px;
|
||||||
height: 46px;
|
height: 46px;
|
||||||
top: calc(14px + var(--stickyTop, 0px));
|
top: calc(14px + var(--stickyTop, 0px));
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: 350px) {
|
@container (max-width: 350px) {
|
||||||
.tkcbzcuz {
|
.footerButton {
|
||||||
> .article {
|
&:not(:last-child) {
|
||||||
> .main {
|
margin-right: 18px;
|
||||||
> .footer {
|
|
||||||
> .button {
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: 300px) {
|
@container (max-width: 300px) {
|
||||||
.tkcbzcuz {
|
.avatar {
|
||||||
> .article {
|
width: 44px;
|
||||||
> .avatar {
|
height: 44px;
|
||||||
width: 44px;
|
}
|
||||||
height: 44px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .main {
|
.footerButton {
|
||||||
> .footer {
|
&:not(:last-child) {
|
||||||
> .button {
|
margin-right: 12px;
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<header class="kkwtjztg">
|
<header :class="$style.root">
|
||||||
<MkA v-once v-user-preview="note.user.id" class="name" :to="userPage(note.user)">
|
<MkA v-once v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)">
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<div v-if="note.user.isBot" class="is-bot">bot</div>
|
<div v-if="note.user.isBot" :class="$style.isBot">bot</div>
|
||||||
<div class="username"><MkAcct :user="note.user"/></div>
|
<div :class="$style.username"><MkAcct :user="note.user"/></div>
|
||||||
<div class="info">
|
<div :class="$style.info">
|
||||||
<MkA class="created-at" :to="notePage(note)">
|
<MkA :to="notePage(note)">
|
||||||
<MkTime :time="note.createdAt"/>
|
<MkTime :time="note.createdAt"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
|
<span v-if="note.visibility !== 'public'" style="margin-left: 0.5em;" :title="i18n.ts._visibility[note.visibility]">
|
||||||
|
@ -32,49 +32,49 @@ defineProps<{
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.kkwtjztg {
|
.root {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
> .name {
|
.name {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 .5em 0 0;
|
margin: 0 .5em 0 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .is-bot {
|
|
||||||
flex-shrink: 0;
|
|
||||||
align-self: center;
|
|
||||||
margin: 0 .5em 0 0;
|
|
||||||
padding: 1px 6px;
|
|
||||||
font-size: 80%;
|
|
||||||
border: solid 0.5px var(--divider);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .username {
|
|
||||||
flex-shrink: 9999999;
|
|
||||||
margin: 0 .5em 0 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .info {
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.isBot {
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-self: center;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
padding: 1px 6px;
|
||||||
|
font-size: 80%;
|
||||||
|
border: solid 0.5px var(--divider);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
flex-shrink: 9999999;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="yohlumlk">
|
<div :class="$style.root">
|
||||||
<MkAvatar class="avatar" :user="note.user"/>
|
<MkAvatar :class="$style.avatar" :user="note.user"/>
|
||||||
<div class="main">
|
<div :class="$style.main">
|
||||||
<MkNoteHeader class="header" :note="note" :mini="true"/>
|
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
|
||||||
<div class="body">
|
<div>
|
||||||
<p v-if="note.cw != null" class="cw">
|
<p v-if="note.cw != null" :class="$style.cw">
|
||||||
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i"/>
|
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :i="$i"/>
|
||||||
<MkCwButton v-model="showContent" :note="note"/>
|
<MkCwButton v-model="showContent" :note="note"/>
|
||||||
</p>
|
</p>
|
||||||
<div v-show="note.cw == null || showContent" class="content">
|
<div v-show="note.cw == null || showContent">
|
||||||
<MkSubNoteContent class="text" :note="note"/>
|
<MkSubNoteContent :class="$style.text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -31,73 +31,60 @@ const props = defineProps<{
|
||||||
const showContent = $ref(false);
|
const showContent = $ref(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.yohlumlk {
|
.root {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
font-size: 0.95em;
|
font-size: 0.95em;
|
||||||
|
}
|
||||||
|
|
||||||
> .avatar {
|
.avatar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 10px 0 0;
|
margin: 0 10px 0 0;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main {
|
.main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
> .header {
|
.header {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .body {
|
.cw {
|
||||||
|
cursor: default;
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
> .cw {
|
.text {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
display: block;
|
margin: 0;
|
||||||
margin: 0;
|
padding: 0;
|
||||||
padding: 0;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
|
|
||||||
> .text {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .content {
|
|
||||||
> .text {
|
|
||||||
cursor: default;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (min-width: 350px) {
|
@container (min-width: 350px) {
|
||||||
.yohlumlk {
|
.avatar {
|
||||||
> .avatar {
|
margin: 0 10px 0 0;
|
||||||
margin: 0 10px 0 0;
|
width: 44px;
|
||||||
width: 44px;
|
height: 44px;
|
||||||
height: 44px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (min-width: 500px) {
|
@container (min-width: 500px) {
|
||||||
.yohlumlk {
|
.avatar {
|
||||||
> .avatar {
|
margin: 0 12px 0 0;
|
||||||
margin: 0 12px 0 0;
|
width: 48px;
|
||||||
width: 48px;
|
height: 48px;
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="wrpstxzv" :class="{ children: depth > 1 }">
|
<div :class="[$style.root, { [$style.children]: depth > 1 }]">
|
||||||
<div class="main">
|
<div :class="$style.main">
|
||||||
<MkAvatar class="avatar" :user="note.user"/>
|
<MkAvatar :class="$style.avatar" :user="note.user"/>
|
||||||
<div class="body">
|
<div :class="$style.body">
|
||||||
<MkNoteHeader class="header" :note="note" :mini="true"/>
|
<MkNoteHeader :class="$style.header" :note="note" :mini="true"/>
|
||||||
<div class="body">
|
<div>
|
||||||
<p v-if="note.cw != null" class="cw">
|
<p v-if="note.cw != null" :class="$style.cw">
|
||||||
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i"/>
|
<Mfm v-if="note.cw != ''" style="margin-right: 8px;" :text="note.cw" :author="note.user" :i="$i"/>
|
||||||
<MkCwButton v-model="showContent" :note="note"/>
|
<MkCwButton v-model="showContent" :note="note"/>
|
||||||
</p>
|
</p>
|
||||||
<div v-show="note.cw == null || showContent" class="content">
|
<div v-show="note.cw == null || showContent">
|
||||||
<MkSubNoteContent class="text" :note="note"/>
|
<MkSubNoteContent :class="$style.text" :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="depth < 5">
|
<template v-if="depth < 5">
|
||||||
<MkNoteSub v-for="reply in replies" :key="reply.id" :note="reply" class="reply" :detail="true" :depth="depth + 1"/>
|
<MkNoteSub v-for="reply in replies" :key="reply.id" :note="reply" :class="$style.reply" :detail="true" :depth="depth + 1"/>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="more">
|
<div v-else :class="$style.more">
|
||||||
<MkA class="text _link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ti ti-chevron-double-right"></i></MkA>
|
<MkA class="_link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ti ti-chevron-double-right"></i></MkA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -57,8 +57,8 @@ if (props.detail) {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.wrpstxzv {
|
.root {
|
||||||
padding: 16px 32px;
|
padding: 16px 32px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
@ -66,62 +66,54 @@ if (props.detail) {
|
||||||
padding: 10px 0 0 16px;
|
padding: 10px 0 0 16px;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .main {
|
.main {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
> .avatar {
|
.avatar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 8px 0 0;
|
margin: 0 8px 0 0;
|
||||||
width: 38px;
|
width: 38px;
|
||||||
height: 38px;
|
height: 38px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .body {
|
.body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
> .header {
|
.header {
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .body {
|
.cw {
|
||||||
> .cw {
|
cursor: default;
|
||||||
cursor: default;
|
display: block;
|
||||||
display: block;
|
margin: 0;
|
||||||
margin: 0;
|
padding: 0;
|
||||||
padding: 0;
|
overflow-wrap: break-word;
|
||||||
overflow-wrap: break-word;
|
}
|
||||||
|
|
||||||
> .text {
|
.text {
|
||||||
margin-right: 8px;
|
margin: 0;
|
||||||
}
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
.reply, .more {
|
||||||
> .text {
|
border-left: solid 0.5px var(--divider);
|
||||||
margin: 0;
|
margin-top: 10px;
|
||||||
padding: 0;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .reply, > .more {
|
.more {
|
||||||
border-left: solid 0.5px var(--divider);
|
padding: 10px 0 0 16px;
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .more {
|
|
||||||
padding: 10px 0 0 16px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: 450px) {
|
@container (max-width: 450px) {
|
||||||
.wrpstxzv {
|
.root {
|
||||||
padding: 14px 16px;
|
padding: 14px 16px;
|
||||||
|
|
||||||
&.children {
|
&.children {
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default="{ items: notes }">
|
<template #default="{ items: notes }">
|
||||||
<div class="giivymft" :class="{ noGap }">
|
<div :class="[$style.root, { [$style.noGap]: noGap }]">
|
||||||
<XList ref="notes" v-slot="{ item: note }" :items="notes" :direction="pagination.reversed ? 'up' : 'down'" :reversed="pagination.reversed" :no-gap="noGap" :ad="true" class="notes">
|
<MkDateSeparatedList ref="notes" v-slot="{ item: note }" :items="notes" :direction="pagination.reversed ? 'up' : 'down'" :reversed="pagination.reversed" :no-gap="noGap" :ad="true" :class="$style.notes">
|
||||||
<XNote :key="note._featuredId_ || note._prId_ || note.id" class="qtqtichx" :note="note"/>
|
<XNote :key="note._featuredId_ || note._prId_ || note.id" :class="$style.note" :note="note"/>
|
||||||
</XList>
|
</MkDateSeparatedList>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import XNote from '@/components/MkNote.vue';
|
import XNote from '@/components/MkNote.vue';
|
||||||
import XList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ defineExpose({
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.giivymft {
|
.root {
|
||||||
&.noGap {
|
&.noGap {
|
||||||
> .notes {
|
> .notes {
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
|
@ -48,7 +48,7 @@ defineExpose({
|
||||||
> .notes {
|
> .notes {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
|
|
||||||
.qtqtichx {
|
.note {
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="elRef" class="qglefbjs" :class="notification.type">
|
<div ref="elRef" :class="$style.root">
|
||||||
<div v-once class="head">
|
<div v-once :class="$style.head">
|
||||||
<MkAvatar v-if="notification.type === 'pollEnded'" class="icon" :user="notification.note.user"/>
|
<MkAvatar v-if="notification.type === 'pollEnded'" :class="$style.icon" :user="notification.note.user"/>
|
||||||
<MkAvatar v-else-if="notification.user" class="icon" :user="notification.user"/>
|
<MkAvatar v-else-if="notification.user" :class="$style.icon" :user="notification.user"/>
|
||||||
<img v-else-if="notification.icon" class="icon" :src="notification.icon" alt=""/>
|
<img v-else-if="notification.icon" :class="$style.icon" :src="notification.icon" alt=""/>
|
||||||
<div class="sub-icon" :class="notification.type">
|
<div :class="[$style.subIcon, $style['t_' + notification.type]]">
|
||||||
<i v-if="notification.type === 'follow'" class="ti ti-plus"></i>
|
<i v-if="notification.type === 'follow'" class="ti ti-plus"></i>
|
||||||
<i v-else-if="notification.type === 'receiveFollowRequest'" class="ti ti-clock"></i>
|
<i v-else-if="notification.type === 'receiveFollowRequest'" class="ti ti-clock"></i>
|
||||||
<i v-else-if="notification.type === 'followRequestAccepted'" class="ti ti-check"></i>
|
<i v-else-if="notification.type === 'followRequestAccepted'" class="ti ti-check"></i>
|
||||||
|
@ -21,46 +21,47 @@
|
||||||
:reaction="notification.reaction ? notification.reaction.replace(/^:(\w+):$/, ':$1@.:') : notification.reaction"
|
:reaction="notification.reaction ? notification.reaction.replace(/^:(\w+):$/, ':$1@.:') : notification.reaction"
|
||||||
:custom-emojis="notification.note.emojis"
|
:custom-emojis="notification.note.emojis"
|
||||||
:no-style="true"
|
:no-style="true"
|
||||||
|
style="width: 100%; height: 100%;"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tail">
|
<div :class="$style.tail">
|
||||||
<header>
|
<header :class="$style.header">
|
||||||
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
|
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
|
||||||
<MkA v-else-if="notification.user" v-user-preview="notification.user.id" class="name" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
<MkA v-else-if="notification.user" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
||||||
<span v-else>{{ notification.header }}</span>
|
<span v-else>{{ notification.header }}</span>
|
||||||
<MkTime v-if="withTime" :time="notification.createdAt" class="time"/>
|
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
||||||
</header>
|
</header>
|
||||||
<div v-once class="content">
|
<div v-once :class="$style.content">
|
||||||
<MkA v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'reaction'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<i class="ti ti-quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
||||||
<i class="ti ti-quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'renote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
|
<MkA v-else-if="notification.type === 'renote'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
|
||||||
<i class="ti ti-quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full"/>
|
<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full"/>
|
||||||
<i class="ti ti-quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'reply'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-else-if="notification.type === 'reply'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'mention'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-else-if="notification.type === 'mention'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'quote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-else-if="notification.type === 'quote'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'pollEnded'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-else-if="notification.type === 'pollEnded'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<i class="ti ti-quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full"/>
|
||||||
<i class="ti ti-quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
</MkA>
|
</MkA>
|
||||||
<span v-else-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ i18n.ts.youGotNewFollower }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
|
<span v-else-if="notification.type === 'follow'" :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.youGotNewFollower }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
|
||||||
<span v-else-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ i18n.ts.followRequestAccepted }}</span>
|
<span v-else-if="notification.type === 'followRequestAccepted'" :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.followRequestAccepted }}</span>
|
||||||
<span v-else-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ i18n.ts.receiveFollowRequest }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ i18n.ts.reject }}</button></div></span>
|
<span v-else-if="notification.type === 'receiveFollowRequest'" :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.receiveFollowRequest }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ i18n.ts.reject }}</button></div></span>
|
||||||
<span v-else-if="notification.type === 'groupInvited'" class="text" style="opacity: 0.6;">{{ i18n.ts.groupInvited }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ i18n.ts.reject }}</button></div></span>
|
<span v-else-if="notification.type === 'groupInvited'" :class="$style.text" style="opacity: 0.6;">{{ i18n.ts.groupInvited }}: <b>{{ notification.invitation.group.name }}</b><div v-if="full && !groupInviteDone"><button class="_textButton" @click="acceptGroupInvitation()">{{ i18n.ts.accept }}</button> | <button class="_textButton" @click="rejectGroupInvitation()">{{ i18n.ts.reject }}</button></div></span>
|
||||||
<span v-else-if="notification.type === 'app'" class="text">
|
<span v-else-if="notification.type === 'app'" :class="$style.text">
|
||||||
<Mfm :text="notification.body" :nowrap="!full"/>
|
<Mfm :text="notification.body" :nowrap="!full"/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -156,8 +157,8 @@ useTooltip(reactionRef, (showing) => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.qglefbjs {
|
.root {
|
||||||
position: relative;
|
position: relative;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 24px 32px;
|
padding: 24px 32px;
|
||||||
|
@ -165,139 +166,135 @@ useTooltip(reactionRef, (showing) => {
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
display: flex;
|
display: flex;
|
||||||
contain: content;
|
contain: content;
|
||||||
|
}
|
||||||
|
|
||||||
> .head {
|
.head {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 42px;
|
width: 42px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
> .icon {
|
.icon {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .sub-icon {
|
.subIcon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
right: -2px;
|
right: -2px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
box-shadow: 0 0 0 3px var(--panel);
|
box-shadow: 0 0 0 3px var(--panel);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
&:empty {
|
&:empty {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
color: #fff;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.follow, &.followRequestAccepted, &.receiveFollowRequest, &.groupInvited {
|
|
||||||
padding: 3px;
|
|
||||||
background: #36aed2;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.renote {
|
|
||||||
padding: 3px;
|
|
||||||
background: #36d298;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.quote {
|
|
||||||
padding: 3px;
|
|
||||||
background: #36d298;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.reply {
|
|
||||||
padding: 3px;
|
|
||||||
background: #007aff;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mention {
|
|
||||||
padding: 3px;
|
|
||||||
background: #88a6b7;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.pollEnded {
|
|
||||||
padding: 3px;
|
|
||||||
background: #88a6b7;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .tail {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
|
|
||||||
> header {
|
|
||||||
display: flex;
|
|
||||||
align-items: baseline;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
> .name {
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
min-width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .time {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .content {
|
|
||||||
> .text {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
|
|
||||||
> i {
|
|
||||||
vertical-align: super;
|
|
||||||
font-size: 50%;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
> i:first-child {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> i:last-child {
|
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.t_follow, .t_followRequestAccepted, .t_receiveFollowRequest, .t_groupInvited {
|
||||||
|
padding: 3px;
|
||||||
|
background: #36aed2;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t_renote {
|
||||||
|
padding: 3px;
|
||||||
|
background: #36d298;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t_quote {
|
||||||
|
padding: 3px;
|
||||||
|
background: #36d298;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t_reply {
|
||||||
|
padding: 3px;
|
||||||
|
background: #007aff;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t_mention {
|
||||||
|
padding: 3px;
|
||||||
|
background: #88a6b7;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.t_pollEnded {
|
||||||
|
padding: 3px;
|
||||||
|
background: #88a6b7;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tail {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerName {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerTime {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quote {
|
||||||
|
vertical-align: super;
|
||||||
|
font-size: 50%;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quote:first-child {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quote:last-child {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
@container (max-width: 600px) {
|
@container (max-width: 600px) {
|
||||||
.qglefbjs {
|
.root {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@container (max-width: 500px) {
|
@container (max-width: 500px) {
|
||||||
.qglefbjs {
|
.root {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default="{ items: notifications }">
|
<template #default="{ items: notifications }">
|
||||||
<XList v-slot="{ item: notification }" class="elsfgstc" :items="notifications" :no-gap="true">
|
<MkDateSeparatedList v-slot="{ item: notification }" class="elsfgstc" :items="notifications" :no-gap="true">
|
||||||
<XNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :key="notification.id" :note="notification.note"/>
|
<XNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :key="notification.id" :note="notification.note"/>
|
||||||
<XNotification v-else :key="notification.id" :notification="notification" :with-time="true" :full="true" class="_panel notification"/>
|
<XNotification v-else :key="notification.id" :notification="notification" :with-time="true" :full="true" class="_panel notification"/>
|
||||||
</XList>
|
</MkDateSeparatedList>
|
||||||
</template>
|
</template>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</template>
|
</template>
|
||||||
|
@ -21,7 +21,7 @@ import { defineComponent, markRaw, onUnmounted, onMounted, computed, shallowRef
|
||||||
import { notificationTypes } from 'misskey-js';
|
import { notificationTypes } from 'misskey-js';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import XNotification from '@/components/MkNotification.vue';
|
import XNotification from '@/components/MkNotification.vue';
|
||||||
import XList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import XNote from '@/components/MkNote.vue';
|
import XNote from '@/components/MkNote.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { stream } from '@/stream';
|
import { stream } from '@/stream';
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Transition :name="$store.state.animation ? 'y' : ''">
|
<TransitionGroup :name="$store.state.animation ? 'x' : ''" tag="div" class="tdflqwzn" :class="{ isMe }">
|
||||||
<TransitionGroup v-if="Object.keys(note.reactions).length > 0" :name="$store.state.animation ? 'x' : ''" tag="div" class="tdflqwzn" :class="{ isMe }">
|
<XReaction v-for="(count, reaction) in note.reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/>
|
||||||
<XReaction v-for="(count, reaction) in note.reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/>
|
</TransitionGroup>
|
||||||
</TransitionGroup>
|
|
||||||
</Transition>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
@ -22,16 +20,6 @@ const isMe = computed(() => $i && $i.id === props.note.userId);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.y-enter-active, .y-leave-active {
|
|
||||||
overflow: clip;
|
|
||||||
max-height: 36px;
|
|
||||||
transition: opacity 0.2s cubic-bezier(0,.5,.5,1), max-height 0.2s cubic-bezier(0,.5,.5,1) !important;
|
|
||||||
}
|
|
||||||
.y-enter-from, .y-leave-to {
|
|
||||||
max-height: 0px;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.x-move, .x-enter-active, .x-leave-active {
|
.x-move, .x-enter-active, .x-leave-active {
|
||||||
transition: opacity 0.2s cubic-bezier(0,.5,.5,1), transform 0.2s cubic-bezier(0,.5,.5,1) !important;
|
transition: opacity 0.2s cubic-bezier(0,.5,.5,1), transform 0.2s cubic-bezier(0,.5,.5,1) !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<Transition :name="$store.state.animation ? 'tooltip' : ''" appear @after-leave="emit('closed')">
|
<Transition
|
||||||
<div v-show="showing" ref="el" class="buebdbiu _acrylic _shadow" :style="{ zIndex, maxWidth: maxWidth + 'px' }">
|
:enter-active-class="$store.state.animation ? $style.transition_tooltip_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_tooltip_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_tooltip_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_tooltip_leaveTo : ''"
|
||||||
|
appear @after-leave="emit('closed')"
|
||||||
|
>
|
||||||
|
<div v-show="showing" ref="el" :class="$style.root" class="_acrylic _shadow" :style="{ zIndex, maxWidth: maxWidth + 'px' }">
|
||||||
<slot>
|
<slot>
|
||||||
<Mfm v-if="asMfm" :text="text"/>
|
<Mfm v-if="asMfm" :text="text"/>
|
||||||
<span v-else>{{ text }}</span>
|
<span v-else>{{ text }}</span>
|
||||||
|
@ -74,20 +80,20 @@ onUnmounted(() => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.tooltip-enter-active,
|
.transition_tooltip_enterActive,
|
||||||
.tooltip-leave-active {
|
.transition_tooltip_leaveActive {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1), opacity 200ms cubic-bezier(0.23, 1, 0.32, 1);
|
transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1), opacity 200ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
}
|
}
|
||||||
.tooltip-enter-from,
|
.transition_tooltip_enterFrom,
|
||||||
.tooltip-leave-active {
|
.transition_tooltip_leaveTo {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: scale(0.75);
|
transform: scale(0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.buebdbiu {
|
.root {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
|
|
|
@ -15,21 +15,21 @@
|
||||||
handle=".handle"
|
handle=".handle"
|
||||||
:animation="150"
|
:animation="150"
|
||||||
:group="{ name: 'SortableMkWidgets' }"
|
:group="{ name: 'SortableMkWidgets' }"
|
||||||
@update:model-value="v => emit('updateWidgets', v)"
|
|
||||||
:class="$style['edit-editing']"
|
:class="$style['edit-editing']"
|
||||||
|
@update:model-value="v => emit('updateWidgets', v)"
|
||||||
>
|
>
|
||||||
<template #item="{element}">
|
<template #item="{element}">
|
||||||
<div :class="[$style.widget, $style['customize-container']]">
|
<div :class="[$style.widget, $style['customize-container']]">
|
||||||
<button :class="$style['customize-container-config']" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button>
|
<button :class="$style['customize-container-config']" class="_button" @click.prevent.stop="configWidget(element.id)"><i class="ti ti-settings"></i></button>
|
||||||
<button :class="$style['customize-container-remove']" class="_button" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button>
|
<button :class="$style['customize-container-remove']" class="_button" @click.prevent.stop="removeWidget(element)"><i class="ti ti-x"></i></button>
|
||||||
<div class="handle">
|
<div class="handle">
|
||||||
<component :is="`mkw-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @update-props="updateWidget(element.id, $event)"/>
|
<component :is="`widget-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="widget" :class="$style['customize-container-handle-widget']" :widget="element" @update-props="updateWidget(element.id, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Sortable>
|
</Sortable>
|
||||||
</template>
|
</template>
|
||||||
<component :is="`mkw-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @update-props="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/>
|
<component :is="`widget-${widget.name}`" v-for="widget in widgets" v-else :key="widget.id" :ref="el => widgetRefs[widget.id] = el" :class="$style.widget" :widget="widget" @update-props="updateWidget(widget.id, $event)" @contextmenu.stop="onContextmenu(widget, $event)"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<span class="mk-acct">
|
<span>
|
||||||
<span class="name">@{{ user.username }}</span>
|
<span>@{{ user.username }}</span>
|
||||||
<span v-if="user.host || detail || $store.state.showFullAcct" class="host">@{{ user.host || host }}</span>
|
<span v-if="user.host || detail || $store.state.showFullAcct" style="opacity: 0.5;">@{{ user.host || host }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -18,10 +18,3 @@ defineProps<{
|
||||||
const host = toUnicode(hostRaw);
|
const host = toUnicode(hostRaw);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.mk-acct {
|
|
||||||
> .host {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<span v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" class="eiwwqkts _noSelect" :class="{ cat: user.isCat, square: $store.state.squareAvatars }" :style="{ color }" :title="acct(user)" @click="onClick">
|
<span v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" class="_noSelect" :style="{ color }" :title="acct(user)" @click="onClick">
|
||||||
<img class="inner" :src="url" decoding="async"/>
|
<img :class="$style.inner" :src="url" decoding="async"/>
|
||||||
<MkUserOnlineIndicator v-if="showIndicator" class="indicator" :user="user"/>
|
<MkUserOnlineIndicator v-if="showIndicator" :class="$style.indicator" :user="user"/>
|
||||||
</span>
|
</span>
|
||||||
<MkA v-else v-user-preview="disablePreview ? undefined : user.id" class="eiwwqkts _noSelect" :class="{ cat: user.isCat, square: $store.state.squareAvatars }" :style="{ color }" :to="userPage(user)" :title="acct(user)" :target="target">
|
<MkA v-else v-user-preview="disablePreview ? undefined : user.id" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :to="userPage(user)" :title="acct(user)" :target="target">
|
||||||
<img class="inner" :src="url" decoding="async"/>
|
<img :class="$style.inner" :src="url" decoding="async"/>
|
||||||
<MkUserOnlineIndicator v-if="showIndicator" class="indicator" :user="user"/>
|
<MkUserOnlineIndicator v-if="showIndicator" :class="$style.indicator" :user="user"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ watch(() => props.user.avatarBlurhash, () => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
@keyframes earwiggleleft {
|
@keyframes earwiggleleft {
|
||||||
from { transform: rotate(37.6deg) skew(30deg); }
|
from { transform: rotate(37.6deg) skew(30deg); }
|
||||||
25% { transform: rotate(10deg) skew(30deg); }
|
25% { transform: rotate(10deg) skew(30deg); }
|
||||||
|
@ -69,74 +69,74 @@ watch(() => props.user.avatarBlurhash, () => {
|
||||||
to { transform: rotate(-37.6deg) skew(-30deg); }
|
to { transform: rotate(-37.6deg) skew(-30deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
.eiwwqkts {
|
.root {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
border-radius: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
overflow: clip;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 20%;
|
||||||
|
height: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.square {
|
||||||
|
border-radius: 20%;
|
||||||
|
|
||||||
> .inner {
|
> .inner {
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
border-radius: 100%;
|
|
||||||
z-index: 1;
|
|
||||||
overflow: clip;
|
|
||||||
object-fit: cover;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .indicator {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 20%;
|
|
||||||
height: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.square {
|
|
||||||
border-radius: 20%;
|
border-radius: 20%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .inner {
|
.cat {
|
||||||
border-radius: 20%;
|
&:before, &:after {
|
||||||
}
|
background: #df548f;
|
||||||
|
border: solid 4px currentColor;
|
||||||
|
box-sizing: border-box;
|
||||||
|
content: '';
|
||||||
|
display: inline-block;
|
||||||
|
height: 50%;
|
||||||
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cat {
|
&:before {
|
||||||
&:before, &:after {
|
border-radius: 0 75% 75%;
|
||||||
background: #df548f;
|
transform: rotate(37.5deg) skew(30deg);
|
||||||
border: solid 4px currentColor;
|
}
|
||||||
box-sizing: border-box;
|
|
||||||
content: '';
|
|
||||||
display: inline-block;
|
|
||||||
height: 50%;
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
border-radius: 75% 0 75% 75%;
|
||||||
|
transform: rotate(-37.5deg) skew(-30deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
&:before {
|
&:before {
|
||||||
border-radius: 0 75% 75%;
|
animation: earwiggleleft 1s infinite;
|
||||||
transform: rotate(37.5deg) skew(30deg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
border-radius: 75% 0 75% 75%;
|
animation: earwiggleright 1s infinite;
|
||||||
transform: rotate(-37.5deg) skew(-30deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
&:before {
|
|
||||||
animation: earwiggleleft 1s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
animation: earwiggleright 1s infinite;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<img v-if="isCustom" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/>
|
<img v-if="isCustom" :class="[$style.root, $style.custom, { [$style.normal]: normal, [$style.noStyle]: noStyle }]" :src="url" :alt="alt" :title="alt" decoding="async"/>
|
||||||
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" decoding="async" @pointerenter="computeTitle"/>
|
<img v-else-if="char && !useOsNativeEmojis" :class="$style.root" :src="url" :alt="alt" decoding="async" @pointerenter="computeTitle"/>
|
||||||
<span v-else-if="char && useOsNativeEmojis" :alt="alt" @pointerenter="computeTitle">{{ char }}</span>
|
<span v-else-if="char && useOsNativeEmojis" :alt="alt" @pointerenter="computeTitle">{{ char }}</span>
|
||||||
<span v-else>{{ emoji }}</span>
|
<span v-else>{{ emoji }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -47,32 +47,32 @@ function computeTitle(event: PointerEvent): void {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.mk-emoji {
|
.root {
|
||||||
|
height: 1.25em;
|
||||||
|
vertical-align: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom {
|
||||||
|
height: 2.5em;
|
||||||
|
vertical-align: middle;
|
||||||
|
transition: transform 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.normal {
|
||||||
height: 1.25em;
|
height: 1.25em;
|
||||||
vertical-align: -0.25em;
|
vertical-align: -0.25em;
|
||||||
|
|
||||||
&.custom {
|
&:hover {
|
||||||
height: 2.5em;
|
transform: none;
|
||||||
vertical-align: middle;
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: scale(1.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.normal {
|
|
||||||
height: 1.25em;
|
|
||||||
vertical-align: -0.25em;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.noStyle {
|
|
||||||
height: auto !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.noStyle {
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<component
|
<component
|
||||||
:is="self ? 'MkA' : 'a'" ref="el" class="ieqqeuvs _link" :[attr]="self ? props.url.substring(local.length) : props.url" :rel="rel" :target="target"
|
:is="self ? 'MkA' : 'a'" ref="el" :class="$style.root" class="_link" :[attr]="self ? props.url.substring(local.length) : props.url" :rel="rel" :target="target"
|
||||||
@contextmenu.stop="() => {}"
|
@contextmenu.stop="() => {}"
|
||||||
>
|
>
|
||||||
<template v-if="!self">
|
<template v-if="!self">
|
||||||
<span class="schema">{{ schema }}//</span>
|
<span :class="$style.schema">{{ schema }}//</span>
|
||||||
<span class="hostname">{{ hostname }}</span>
|
<span :class="$style.hostname">{{ hostname }}</span>
|
||||||
<span v-if="port != ''" class="port">:{{ port }}</span>
|
<span v-if="port != ''" :class="$style.port">:{{ port }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="pathname === '/' && self">
|
<template v-if="pathname === '/' && self">
|
||||||
<span class="self">{{ hostname }}</span>
|
<span :class="$style.self">{{ hostname }}</span>
|
||||||
</template>
|
</template>
|
||||||
<span v-if="pathname != ''" class="pathname">{{ self ? pathname.substring(1) : pathname }}</span>
|
<span v-if="pathname != ''" :class="$style.pathname">{{ self ? pathname.substring(1) : pathname }}</span>
|
||||||
<span class="query">{{ query }}</span>
|
<span :class="$style.query">{{ query }}</span>
|
||||||
<span class="hash">{{ hash }}</span>
|
<span :class="$style.hash">{{ hash }}</span>
|
||||||
<i v-if="target === '_blank'" class="ti ti-external-link icon"></i>
|
<i v-if="target === '_blank'" class="ti ti-external-link icon"></i>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
@ -53,37 +53,37 @@ const attr = self ? 'to' : 'href';
|
||||||
const target = self ? null : '_blank';
|
const target = self ? null : '_blank';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.ieqqeuvs {
|
.root {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
> .icon {
|
.icon {
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .self {
|
.self {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .schema {
|
.schema {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .hostname {
|
.hostname {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .pathname {
|
.pathname {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .query {
|
.query {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .hash {
|
.hash {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import MkLink from '@/components/MkLink.vue';
|
||||||
import MkMention from '@/components/MkMention.vue';
|
import MkMention from '@/components/MkMention.vue';
|
||||||
import MkEmoji from '@/components/global/MkEmoji.vue';
|
import MkEmoji from '@/components/global/MkEmoji.vue';
|
||||||
import { concat } from '@/scripts/array';
|
import { concat } from '@/scripts/array';
|
||||||
import MkFormula from '@/components/MkFormula.vue';
|
|
||||||
import MkCode from '@/components/MkCode.vue';
|
import MkCode from '@/components/MkCode.vue';
|
||||||
import MkGoogle from '@/components/MkGoogle.vue';
|
import MkGoogle from '@/components/MkGoogle.vue';
|
||||||
import MkSparkle from '@/components/MkSparkle.vue';
|
import MkSparkle from '@/components/MkSparkle.vue';
|
||||||
|
@ -273,7 +272,7 @@ export default defineComponent({
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
emoji: `:${token.props.name}:`,
|
emoji: `:${token.props.name}:`,
|
||||||
normal: this.plain,
|
normal: this.plain,
|
||||||
host: this.author?.host,
|
host: this.author.host,
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,19 +285,11 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'mathInline': {
|
case 'mathInline': {
|
||||||
return [h(MkFormula, {
|
return [h('code', genEl(token.props.formula))];
|
||||||
key: Math.random(),
|
|
||||||
formula: token.props.formula,
|
|
||||||
block: false,
|
|
||||||
})];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'mathBlock': {
|
case 'mathBlock': {
|
||||||
return [h(MkFormula, {
|
return [h('code', genEl(token.props.formula))];
|
||||||
key: Math.random(),
|
|
||||||
formula: token.props.formula,
|
|
||||||
block: true,
|
|
||||||
})];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'search': {
|
case 'search': {
|
||||||
|
|
|
@ -4,89 +4,11 @@ import { Component, markRaw, Ref, ref, defineAsyncComponent } from 'vue';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { apiUrl, url } from '@/config';
|
|
||||||
import MkPostFormDialog from '@/components/MkPostFormDialog.vue';
|
import MkPostFormDialog from '@/components/MkPostFormDialog.vue';
|
||||||
import MkWaitingDialog from '@/components/MkWaitingDialog.vue';
|
import MkWaitingDialog from '@/components/MkWaitingDialog.vue';
|
||||||
import { MenuItem } from '@/types/menu';
|
import { MenuItem } from '@/types/menu';
|
||||||
import { $i } from '@/account';
|
import { pendingApiRequestsCount, api, apiGet } from '@/scripts/api';
|
||||||
|
export { pendingApiRequestsCount, api, apiGet };
|
||||||
export const pendingApiRequestsCount = ref(0);
|
|
||||||
|
|
||||||
const apiClient = new Misskey.api.APIClient({
|
|
||||||
origin: url,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const api = ((endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) => {
|
|
||||||
pendingApiRequestsCount.value++;
|
|
||||||
|
|
||||||
const onFinally = () => {
|
|
||||||
pendingApiRequestsCount.value--;
|
|
||||||
};
|
|
||||||
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
|
||||||
// Append a credential
|
|
||||||
if ($i) (data as any).i = $i.token;
|
|
||||||
if (token !== undefined) (data as any).i = token;
|
|
||||||
|
|
||||||
// Send request
|
|
||||||
window.fetch(endpoint.indexOf('://') > -1 ? endpoint : `${apiUrl}/${endpoint}`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
credentials: 'omit',
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
}).then(async (res) => {
|
|
||||||
const body = res.status === 204 ? null : await res.json();
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
resolve(body);
|
|
||||||
} else if (res.status === 204) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
reject(body.error);
|
|
||||||
}
|
|
||||||
}).catch(reject);
|
|
||||||
});
|
|
||||||
|
|
||||||
promise.then(onFinally, onFinally);
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}) as typeof apiClient.request;
|
|
||||||
|
|
||||||
export const apiGet = ((endpoint: string, data: Record<string, any> = {}) => {
|
|
||||||
pendingApiRequestsCount.value++;
|
|
||||||
|
|
||||||
const onFinally = () => {
|
|
||||||
pendingApiRequestsCount.value--;
|
|
||||||
};
|
|
||||||
|
|
||||||
const query = new URLSearchParams(data);
|
|
||||||
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
|
||||||
// Send request
|
|
||||||
window.fetch(`${apiUrl}/${endpoint}?${query}`, {
|
|
||||||
method: 'GET',
|
|
||||||
credentials: 'omit',
|
|
||||||
cache: 'default',
|
|
||||||
}).then(async (res) => {
|
|
||||||
const body = res.status === 204 ? null : await res.json();
|
|
||||||
|
|
||||||
if (res.status === 200) {
|
|
||||||
resolve(body);
|
|
||||||
} else if (res.status === 204) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
reject(body.error);
|
|
||||||
}
|
|
||||||
}).catch(reject);
|
|
||||||
});
|
|
||||||
|
|
||||||
promise.then(onFinally, onFinally);
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
}) as typeof apiClient.request;
|
|
||||||
|
|
||||||
export const apiWithDialog = ((
|
export const apiWithDialog = ((
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<XList v-slot="{ item }" :items="items" :direction="'down'" :no-gap="false" :ad="false">
|
<MkDateSeparatedList v-slot="{ item }" :items="items" :direction="'down'" :no-gap="false" :ad="false">
|
||||||
<XNote :key="item.id" :note="item.note" :class="$style.note"/>
|
<XNote :key="item.id" :note="item.note" :class="$style.note"/>
|
||||||
</XList>
|
</MkDateSeparatedList>
|
||||||
</template>
|
</template>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import XNote from '@/components/MkNote.vue';
|
import XNote from '@/components/MkNote.vue';
|
||||||
import XList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default="{ items: messages, fetching: pFetching }">
|
<template #default="{ items: messages, fetching: pFetching }">
|
||||||
<XList
|
<MkDateSeparatedList
|
||||||
v-if="messages.length > 0"
|
v-if="messages.length > 0"
|
||||||
v-slot="{ item: message }"
|
v-slot="{ item: message }"
|
||||||
:class="{ messages: true, 'deny-move-transition': pFetching }"
|
:class="{ messages: true, 'deny-move-transition': pFetching }"
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
reversed
|
reversed
|
||||||
>
|
>
|
||||||
<XMessage :key="message.id" :message="message" :is-group="group != null"/>
|
<XMessage :key="message.id" :message="message" :is-group="group != null"/>
|
||||||
</XList>
|
</MkDateSeparatedList>
|
||||||
</template>
|
</template>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,7 +55,7 @@ import * as Misskey from 'misskey-js';
|
||||||
import * as Acct from 'misskey-js/built/acct';
|
import * as Acct from 'misskey-js/built/acct';
|
||||||
import XMessage from './messaging-room.message.vue';
|
import XMessage from './messaging-room.message.vue';
|
||||||
import XForm from './messaging-room.form.vue';
|
import XForm from './messaging-room.form.vue';
|
||||||
import XList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { isBottomVisible, onScrollBottom, scrollToBottom } from '@/scripts/scroll';
|
import { isBottomVisible, onScrollBottom, scrollToBottom } from '@/scripts/scroll';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
@ -351,7 +351,6 @@ definePageMetadata(computed(() => !fetching ? user ? {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
bottom: calc(env(safe-area-inset-bottom, 0px) + 8px);
|
|
||||||
|
|
||||||
> .new-message {
|
> .new-message {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -114,16 +114,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="section">
|
|
||||||
<div class="title">{{ i18n.ts._mfm.inlineMath }}</div>
|
|
||||||
<div class="content">
|
|
||||||
<p>{{ i18n.ts._mfm.inlineMathDescription }}</p>
|
|
||||||
<div class="preview">
|
|
||||||
<Mfm :text="preview_inlineMath"/>
|
|
||||||
<MkTextarea v-model="preview_inlineMath"><template #label>MFM</template></MkTextarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- deprecated
|
<!-- deprecated
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="title">{{ i18n.ts._mfm.search }}</div>
|
<div class="title">{{ i18n.ts._mfm.search }}</div>
|
||||||
|
@ -329,7 +319,6 @@ let preview_small = $ref(`<small>${i18n.ts._mfm.dummy}</small>`);
|
||||||
let preview_center = $ref(`<center>${i18n.ts._mfm.dummy}</center>`);
|
let preview_center = $ref(`<center>${i18n.ts._mfm.dummy}</center>`);
|
||||||
let preview_inlineCode = $ref('`<: "Hello, world!"`');
|
let preview_inlineCode = $ref('`<: "Hello, world!"`');
|
||||||
let preview_blockCode = $ref('```\n~ (#i, 100) {\n\t<: ? ((i % 15) = 0) "FizzBuzz"\n\t\t.? ((i % 3) = 0) "Fizz"\n\t\t.? ((i % 5) = 0) "Buzz"\n\t\t. i\n}\n```');
|
let preview_blockCode = $ref('```\n~ (#i, 100) {\n\t<: ? ((i % 15) = 0) "FizzBuzz"\n\t\t.? ((i % 3) = 0) "Fizz"\n\t\t.? ((i % 5) = 0) "Buzz"\n\t\t. i\n}\n```');
|
||||||
let preview_inlineMath = $ref('\\(x= \\frac{-b\' \\pm \\sqrt{(b\')^2-ac}}{a}\\)');
|
|
||||||
let preview_quote = $ref(`> ${i18n.ts._mfm.dummy}`);
|
let preview_quote = $ref(`> ${i18n.ts._mfm.dummy}`);
|
||||||
let preview_search = $ref(`${i18n.ts._mfm.dummy} 検索`);
|
let preview_search = $ref(`${i18n.ts._mfm.dummy} 検索`);
|
||||||
let preview_jelly = $ref('$[jelly 🍮] $[jelly.speed=5s 🍮]');
|
let preview_jelly = $ref('$[jelly 🍮] $[jelly.speed=5s 🍮]');
|
||||||
|
|
|
@ -2,15 +2,14 @@
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="headerTabs" :display-my-avatar="true"/></template>
|
<template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="headerTabs" :display-my-avatar="true"/></template>
|
||||||
<MkSpacer :content-max="800">
|
<MkSpacer :content-max="800">
|
||||||
<div ref="rootEl" v-hotkey.global="keymap" class="cmuxhskf">
|
<div ref="rootEl" v-hotkey.global="keymap">
|
||||||
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _panel" style="margin-bottom: var(--margin);"/>
|
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="_panel" style="margin-bottom: var(--margin);"/>
|
||||||
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/>
|
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/>
|
||||||
|
|
||||||
<div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div>
|
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div>
|
||||||
<div class="tl">
|
<div :class="$style.tl">
|
||||||
<XTimeline
|
<XTimeline
|
||||||
ref="tl" :key="src"
|
ref="tl" :key="src"
|
||||||
class="tl"
|
|
||||||
:src="src"
|
:src="src"
|
||||||
:sound="true"
|
:sound="true"
|
||||||
@queue="queueUpdated"
|
@queue="queueUpdated"
|
||||||
|
@ -154,30 +153,28 @@ definePageMetadata(computed(() => ({
|
||||||
})));
|
})));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.cmuxhskf {
|
.new {
|
||||||
> .new {
|
position: sticky;
|
||||||
position: sticky;
|
top: calc(var(--stickyTop, 0px) + 16px);
|
||||||
top: calc(var(--stickyTop, 0px) + 16px);
|
z-index: 1000;
|
||||||
z-index: 1000;
|
width: 100%;
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
> button {
|
> button {
|
||||||
display: block;
|
display: block;
|
||||||
margin: var(--margin) auto 0 auto;
|
margin: var(--margin) auto 0 auto;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border-radius: 32px;
|
border-radius: 32px;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .post-form {
|
|
||||||
border-radius: var(--radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .tl {
|
|
||||||
background: var(--bg);
|
|
||||||
border-radius: var(--radius);
|
|
||||||
overflow: clip;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.postForm {
|
||||||
|
border-radius: var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tl {
|
||||||
|
background: var(--bg);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { Endpoints } from 'misskey-js/built/api.types';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { apiUrl } from '@/config';
|
||||||
|
import { $i } from '@/account';
|
||||||
|
export const pendingApiRequestsCount = ref(0);
|
||||||
|
|
||||||
|
// Implements Misskey.api.ApiClient.request
|
||||||
|
export function api<E extends keyof Endpoints, P extends Endpoints[E]['req']>(endpoint: E, data: P = {} as any, token?: string | null | undefined): Promise<Endpoints[E]['res']> {
|
||||||
|
pendingApiRequestsCount.value++;
|
||||||
|
|
||||||
|
const onFinally = () => {
|
||||||
|
pendingApiRequestsCount.value--;
|
||||||
|
};
|
||||||
|
|
||||||
|
const promise = new Promise<Endpoints[E]['res'] | void>((resolve, reject) => {
|
||||||
|
// Append a credential
|
||||||
|
if ($i) (data as any).i = $i.token;
|
||||||
|
if (token !== undefined) (data as any).i = token;
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
window.fetch(endpoint.indexOf('://') > -1 ? endpoint : `${apiUrl}/${endpoint}`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
credentials: 'omit',
|
||||||
|
cache: 'no-cache',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
}).then(async (res) => {
|
||||||
|
const body = res.status === 204 ? null : await res.json();
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
resolve(body);
|
||||||
|
} else if (res.status === 204) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(body.error);
|
||||||
|
}
|
||||||
|
}).catch(reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.then(onFinally, onFinally);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Misskey.api.ApiClient.request
|
||||||
|
export function apiGet<E extends keyof Endpoints, P extends Endpoints[E]['req']>(endpoint: E, data: P = {} as any): Promise<Endpoints[E]['res']> {
|
||||||
|
pendingApiRequestsCount.value++;
|
||||||
|
|
||||||
|
const onFinally = () => {
|
||||||
|
pendingApiRequestsCount.value--;
|
||||||
|
};
|
||||||
|
|
||||||
|
const query = new URLSearchParams(data as any);
|
||||||
|
|
||||||
|
const promise = new Promise<Endpoints[E]['res'] | void>((resolve, reject) => {
|
||||||
|
// Send request
|
||||||
|
window.fetch(`${apiUrl}/${endpoint}?${query}`, {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'omit',
|
||||||
|
cache: 'default',
|
||||||
|
}).then(async (res) => {
|
||||||
|
const body = res.status === 204 ? null : await res.json();
|
||||||
|
|
||||||
|
if (res.status === 200) {
|
||||||
|
resolve(body);
|
||||||
|
} else if (res.status === 204) {
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject(body.error);
|
||||||
|
}
|
||||||
|
}).catch(reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.then(onFinally, onFinally);
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ export class StickySidebar {
|
||||||
private isTop = false;
|
private isTop = false;
|
||||||
private isBottom = false;
|
private isBottom = false;
|
||||||
private offsetTop: number;
|
private offsetTop: number;
|
||||||
private globalHeaderHeight: number = 59;
|
private globalHeaderHeight = 59;
|
||||||
|
|
||||||
constructor(container: StickySidebar['container'], marginTop = 0, globalHeaderHeight = 0) {
|
constructor(container: StickySidebar['container'], marginTop = 0, globalHeaderHeight = 0) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
--marginHalf: 10px;
|
--marginHalf: 10px;
|
||||||
|
|
||||||
--margin: var(--marginFull);
|
--margin: var(--marginFull);
|
||||||
|
--minBottomSpacing: 0px;
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
--margin: var(--marginHalf);
|
--margin: var(--marginHalf);
|
||||||
|
--minBottomSpacing: calc(72px + max(12px, env(safe-area-inset-bottom, 0px)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//--ad: rgb(255 169 0 / 10%);
|
//--ad: rgb(255 169 0 / 10%);
|
||||||
|
|
|
@ -9,8 +9,15 @@
|
||||||
|
|
||||||
<XUpload v-if="uploads.length > 0"/>
|
<XUpload v-if="uploads.length > 0"/>
|
||||||
|
|
||||||
<TransitionGroup :name="$store.state.animation ? 'notification' : ''" tag="div" class="notifications">
|
<TransitionGroup
|
||||||
<XNotification v-for="notification in notifications" :key="notification.id" :notification="notification" class="notification"/>
|
tag="div" :class="$style.notifications"
|
||||||
|
:move-class="$store.state.animation ? $style.transition_notification_move : ''"
|
||||||
|
:enter-active-class="$store.state.animation ? $style.transition_notification_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_notification_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_notification_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_notification_leaveTo : ''"
|
||||||
|
>
|
||||||
|
<XNotification v-for="notification in notifications" :key="notification.id" :notification="notification" :class="$style.notification"/>
|
||||||
</TransitionGroup>
|
</TransitionGroup>
|
||||||
|
|
||||||
<XStreamIndicator/>
|
<XStreamIndicator/>
|
||||||
|
@ -73,11 +80,14 @@ if ($i) {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.notification-move, .notification-enter-active, .notification-leave-active {
|
.transition_notification_move,
|
||||||
|
.transition_notification_enterActive,
|
||||||
|
.transition_notification_leaveActive {
|
||||||
transition: opacity 0.3s, transform 0.3s !important;
|
transition: opacity 0.3s, transform 0.3s !important;
|
||||||
}
|
}
|
||||||
.notification-enter-from, .notification-leave-to {
|
.transition_notification_enterFrom,
|
||||||
|
.transition_notification_leaveTo {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-250px);
|
transform: translateX(-250px);
|
||||||
}
|
}
|
||||||
|
@ -91,31 +101,28 @@ if ($i) {
|
||||||
padding: 0 32px;
|
padding: 0 32px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
container-type: inline-size;
|
container-type: inline-size;
|
||||||
|
}
|
||||||
|
|
||||||
> .notification {
|
.notification {
|
||||||
& + .notification {
|
& + .notification {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 700px) {
|
@media (max-width: 500px) {
|
||||||
|
.notifications {
|
||||||
top: initial;
|
top: initial;
|
||||||
bottom: 112px;
|
bottom: calc(var(--minBottomSpacing) + var(--margin));
|
||||||
padding: 0 16px;
|
padding: 0 var(--margin);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
|
|
||||||
> .notification {
|
|
||||||
& + .notification {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
.notification {
|
||||||
bottom: calc(env(safe-area-inset-bottom, 0px) + 92px);
|
& + .notification {
|
||||||
padding: 0 8px;
|
margin-top: 0;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -38,8 +38,8 @@ onUnmounted(() => {
|
||||||
.nsbbhtug {
|
.nsbbhtug {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 16385;
|
z-index: 16385;
|
||||||
bottom: 8px;
|
bottom: calc(var(--minBottomSpacing) + var(--margin));
|
||||||
right: 8px;
|
right: var(--margin);
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<XSidebar/>
|
<XSidebar/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else ref="widgetsLeft" class="widgets left">
|
<div v-else ref="widgetsLeft" class="widgets left">
|
||||||
<XWidgets place="left" :classic="true" @mounted="attachSticky(widgetsLeft)"/>
|
<XWidgets place="left" :margin-top="'var(--margin)'" @mounted="attachSticky(widgetsLeft)"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main class="main" :style="{ background: pageMetadata?.value?.bg }" @contextmenu.stop="onContextmenu">
|
<main class="main" :style="{ background: pageMetadata?.value?.bg }" @contextmenu.stop="onContextmenu">
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<div v-if="isDesktop" ref="widgetsRight" class="widgets right">
|
<div v-if="isDesktop" ref="widgetsRight" class="widgets right">
|
||||||
<XWidgets :place="showMenuOnTop ? 'right' : null" :classic="true" @mounted="attachSticky(widgetsRight)"/>
|
<XWidgets :place="showMenuOnTop ? 'right' : null" :margin-top="showMenuOnTop ? '0' : 'var(--margin)'" @mounted="attachSticky(widgetsRight)"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ provide('shouldHeaderThin', showMenuOnTop);
|
||||||
provide('forceSpacerMin', true);
|
provide('forceSpacerMin', true);
|
||||||
|
|
||||||
function attachSticky(el) {
|
function attachSticky(el) {
|
||||||
const sticky = new StickySidebar(el, defaultStore.state.menuDisplay === 'top' ? 0 : 16, defaultStore.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す
|
const sticky = new StickySidebar(el, 0, defaultStore.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す
|
||||||
window.addEventListener('scroll', () => {
|
window.addEventListener('scroll', () => {
|
||||||
sticky.calc(window.scrollY);
|
sticky.calc(window.scrollY);
|
||||||
}, { passive: true });
|
}, { passive: true });
|
||||||
|
@ -248,7 +248,6 @@ onMounted(() => {
|
||||||
> .widgets {
|
> .widgets {
|
||||||
//--panelBorder: none;
|
//--panelBorder: none;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
margin-top: 16px;
|
|
||||||
|
|
||||||
@media (max-width: $widgets-hide-threshold) {
|
@media (max-width: $widgets-hide-threshold) {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :class="[$style.root, { [$style.rootIsMobile]: isMobile }]">
|
||||||
class="mk-deck" :class="[{ isMobile }]"
|
|
||||||
>
|
|
||||||
<XSidebar v-if="!isMobile"/>
|
<XSidebar v-if="!isMobile"/>
|
||||||
|
|
||||||
<div class="main">
|
<div :class="$style.main">
|
||||||
<XStatusBars class="statusbars"/>
|
<XStatusBars/>
|
||||||
<div ref="columnsEl" class="columns" :class="deckStore.reactiveState.columnAlign.value" @contextmenu.self.prevent="onContextmenu">
|
<div ref="columnsEl" :class="[$style.columns, deckStore.reactiveState.columnAlign.value]" @contextmenu.self.prevent="onContextmenu">
|
||||||
<template v-for="ids in layout">
|
<template v-for="ids in layout">
|
||||||
<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
|
<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
|
||||||
<section
|
<section
|
||||||
v-if="ids.length > 1"
|
v-if="ids.length > 1"
|
||||||
class="folder column"
|
:class="$style.folder"
|
||||||
:style="columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }"
|
:style="columns.filter(c => ids.includes(c.id)).some(c => c.flexible) ? { flex: 1, minWidth: '350px' } : { width: Math.max(...columns.filter(c => ids.includes(c.id)).map(c => c.width)) + 'px' }"
|
||||||
>
|
>
|
||||||
<DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :is-stacked="true" @parent-focus="moveFocus(id, $event)"/>
|
<DeckColumnCore v-for="id in ids" :ref="id" :key="id" :column="columns.find(c => c.id === id)" :is-stacked="true" @parent-focus="moveFocus(id, $event)"/>
|
||||||
|
@ -20,51 +18,64 @@
|
||||||
v-else
|
v-else
|
||||||
:ref="ids[0]"
|
:ref="ids[0]"
|
||||||
:key="ids[0]"
|
:key="ids[0]"
|
||||||
class="column"
|
:class="$style.column"
|
||||||
:column="columns.find(c => c.id === ids[0])"
|
:column="columns.find(c => c.id === ids[0])"
|
||||||
:is-stacked="false"
|
:is-stacked="false"
|
||||||
:style="columns.find(c => c.id === ids[0])!.flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0])!.width + 'px' }"
|
:style="columns.find(c => c.id === ids[0])!.flexible ? { flex: 1, minWidth: '350px' } : { width: columns.find(c => c.id === ids[0])!.width + 'px' }"
|
||||||
@parent-focus="moveFocus(ids[0], $event)"
|
@parent-focus="moveFocus(ids[0], $event)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="layout.length === 0" class="intro _panel">
|
<div v-if="layout.length === 0" class="_panel" :class="$style.onboarding">
|
||||||
<div>{{ i18n.ts._deck.introduction }}</div>
|
<div>{{ i18n.ts._deck.introduction }}</div>
|
||||||
<MkButton primary class="add" @click="addColumn">{{ i18n.ts._deck.addColumn }}</MkButton>
|
<MkButton primary style="margin: 1em auto;" @click="addColumn">{{ i18n.ts._deck.addColumn }}</MkButton>
|
||||||
<div>{{ i18n.ts._deck.introduction2 }}</div>
|
<div>{{ i18n.ts._deck.introduction2 }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="sideMenu">
|
<div :class="$style.sideMenu">
|
||||||
<div class="top">
|
<div :class="$style.sideMenuTop">
|
||||||
<button v-tooltip.noDelay.left="`${i18n.ts._deck.profile}: ${deckStore.state.profile}`" class="_button button" @click="changeProfile"><i class="ti ti-caret-down"></i></button>
|
<button v-tooltip.noDelay.left="`${i18n.ts._deck.profile}: ${deckStore.state.profile}`" :class="$style.sideMenuButton" class="_button" @click="changeProfile"><i class="ti ti-caret-down"></i></button>
|
||||||
<button v-tooltip.noDelay.left="i18n.ts._deck.deleteProfile" class="_button button" @click="deleteProfile"><i class="ti ti-trash"></i></button>
|
<button v-tooltip.noDelay.left="i18n.ts._deck.deleteProfile" :class="$style.sideMenuButton" class="_button" @click="deleteProfile"><i class="ti ti-trash"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="middle">
|
<div :class="$style.sideMenuMiddle">
|
||||||
<button v-tooltip.noDelay.left="i18n.ts._deck.addColumn" class="_button button" @click="addColumn"><i class="ti ti-plus"></i></button>
|
<button v-tooltip.noDelay.left="i18n.ts._deck.addColumn" :class="$style.sideMenuButton" class="_button" @click="addColumn"><i class="ti ti-plus"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom">
|
<div :class="$style.sideMenuBottom">
|
||||||
<button v-tooltip.noDelay.left="i18n.ts.settings" class="_button button settings" @click="showSettings"><i class="ti ti-settings"></i></button>
|
<button v-tooltip.noDelay.left="i18n.ts.settings" :class="$style.sideMenuButton" class="_button" @click="showSettings"><i class="ti ti-settings"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isMobile" class="buttons">
|
<div v-if="isMobile" :class="$style.nav">
|
||||||
<button class="button nav _button" @click="drawerMenuShowing = true"><i class="ti ti-menu-2"></i><span v-if="menuIndicated" class="indicator"><i class="_indicatorCircle"></i></span></button>
|
<button :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
|
||||||
<button class="button home _button" @click="mainRouter.push('/')"><i class="ti ti-home"></i></button>
|
<button :class="$style.navButton" class="_button" @click="mainRouter.push('/')"><i :class="$style.navButtonIcon" class="ti ti-home"></i></button>
|
||||||
<button class="button notifications _button" @click="mainRouter.push('/my/notifications')"><i class="ti ti-bell"></i><span v-if="$i?.hasUnreadNotification" class="indicator"><i class="_indicatorCircle"></i></span></button>
|
<button :class="$style.navButton" class="_button" @click="mainRouter.push('/my/notifications')"><i :class="$style.navButtonIcon" class="ti ti-bell"></i><span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
|
||||||
<button class="button post _button" @click="os.post()"><i class="ti ti-pencil"></i></button>
|
<button :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Transition :name="$store.state.animation ? 'menu-back' : ''">
|
<Transition
|
||||||
|
:enter-active-class="$store.state.animation ? $style.transition_menuDrawerBg_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="drawerMenuShowing"
|
v-if="drawerMenuShowing"
|
||||||
class="menu-back _modalBg"
|
:class="$style.menuBg"
|
||||||
|
class="_modalBg"
|
||||||
@click="drawerMenuShowing = false"
|
@click="drawerMenuShowing = false"
|
||||||
@touchstart.passive="drawerMenuShowing = false"
|
@touchstart.passive="drawerMenuShowing = false"
|
||||||
></div>
|
></div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<Transition :name="$store.state.animation ? 'menu' : ''">
|
<Transition
|
||||||
<XDrawerMenu v-if="drawerMenuShowing" class="menu"/>
|
:enter-active-class="$store.state.animation ? $style.transition_menuDrawer_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_menuDrawer_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_menuDrawer_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_menuDrawer_leaveTo : ''"
|
||||||
|
>
|
||||||
|
<div v-if="drawerMenuShowing" :class="$style.menu">
|
||||||
|
<XDrawerMenu/>
|
||||||
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<XCommon/>
|
<XCommon/>
|
||||||
|
@ -223,30 +234,30 @@ async function deleteProfile() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.menu-enter-active,
|
.transition_menuDrawerBg_enterActive,
|
||||||
.menu-leave-active {
|
.transition_menuDrawerBg_leaveActive {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
.transition_menuDrawerBg_enterFrom,
|
||||||
|
.transition_menuDrawerBg_leaveTo {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.transition_menuDrawer_enterActive,
|
||||||
|
.transition_menuDrawer_leaveActive {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
}
|
}
|
||||||
.menu-enter-from,
|
.transition_menuDrawer_enterFrom,
|
||||||
.menu-leave-active {
|
.transition_menuDrawer_leaveTo {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-240px);
|
transform: translateX(-240px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-back-enter-active,
|
.root {
|
||||||
.menu-back-leave-active {
|
|
||||||
opacity: 1;
|
|
||||||
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
||||||
}
|
|
||||||
.menu-back-enter-from,
|
|
||||||
.menu-back-leave-active {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mk-deck {
|
|
||||||
$nav-hide-threshold: 650px; // TODO: どこかに集約したい
|
$nav-hide-threshold: 650px; // TODO: どこかに集約したい
|
||||||
|
|
||||||
--margin: var(--marginHalf);
|
--margin: var(--marginHalf);
|
||||||
|
@ -257,178 +268,170 @@ async function deleteProfile() {
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
&.isMobile {
|
.rootIsMobile {
|
||||||
padding-bottom: 100px;
|
padding-bottom: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main {
|
.main {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
> .columns {
|
.columns {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: clip;
|
overflow-y: clip;
|
||||||
|
|
||||||
&.center {
|
&.center {
|
||||||
> .column:first-of-type {
|
> .column:first-of-type {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
|
||||||
|
|
||||||
> .column:last-of-type {
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .column {
|
|
||||||
flex-shrink: 0;
|
|
||||||
border-right: solid var(--deckDividerThickness) var(--deckDivider);
|
|
||||||
|
|
||||||
&:first-of-type {
|
|
||||||
border-left: solid var(--deckDividerThickness) var(--deckDivider);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.folder {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
> *:not(:last-of-type) {
|
|
||||||
border-bottom: solid var(--deckDividerThickness) var(--deckDivider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .intro {
|
|
||||||
padding: 32px;
|
|
||||||
height: min-content;
|
|
||||||
text-align: center;
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
> .add {
|
|
||||||
margin: 1em auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .sideMenu {
|
|
||||||
flex-shrink: 0;
|
|
||||||
margin-right: 0;
|
|
||||||
margin-left: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
width: 32px;
|
|
||||||
|
|
||||||
> .top, > .middle, > .bottom {
|
|
||||||
> .button {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .top {
|
|
||||||
margin-bottom: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .middle {
|
|
||||||
margin-top: auto;
|
|
||||||
margin-bottom: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .bottom {
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
> .buttons {
|
> .column:last-of-type {
|
||||||
position: fixed;
|
margin-right: auto;
|
||||||
z-index: 1000;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
|
|
||||||
> .button {
|
|
||||||
position: relative;
|
|
||||||
flex: 1;
|
|
||||||
padding: 0;
|
|
||||||
margin: auto;
|
|
||||||
height: 64px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: var(--panel);
|
|
||||||
color: var(--fg);
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
|
||||||
height: 60px;
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--X2);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .indicator {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
color: var(--indicator);
|
|
||||||
font-size: 16px;
|
|
||||||
animation: blink 1s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
> .menu-back {
|
|
||||||
z-index: 1001;
|
.column {
|
||||||
}
|
flex-shrink: 0;
|
||||||
|
border-right: solid var(--deckDividerThickness) var(--deckDivider);
|
||||||
> .menu {
|
|
||||||
position: fixed;
|
&:first-of-type {
|
||||||
top: 0;
|
border-left: solid var(--deckDividerThickness) var(--deckDivider);
|
||||||
left: 0;
|
}
|
||||||
z-index: 1001;
|
}
|
||||||
height: 100dvh;
|
|
||||||
width: 240px;
|
.folder {
|
||||||
box-sizing: border-box;
|
composes: column;
|
||||||
contain: strict;
|
display: flex;
|
||||||
overflow: auto;
|
flex-direction: column;
|
||||||
overscroll-behavior: contain;
|
|
||||||
background: var(--navBg);
|
> *:not(:last-of-type) {
|
||||||
}
|
border-bottom: solid var(--deckDividerThickness) var(--deckDivider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding {
|
||||||
|
padding: 32px;
|
||||||
|
height: min-content;
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideMenu {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideMenuButton {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideMenuTop {
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideMenuMiddle {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sideMenuBottom {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuBg {
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1001;
|
||||||
|
height: 100dvh;
|
||||||
|
width: 240px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
contain: strict;
|
||||||
|
overflow: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
background: var(--navBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 12px 12px max(12px, env(safe-area-inset-bottom, 0px)) 12px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
|
grid-gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-backdrop-filter: var(--blur, blur(32px));
|
||||||
|
backdrop-filter: var(--blur, blur(32px));
|
||||||
|
background-color: var(--header);
|
||||||
|
border-top: solid 0.5px var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navButton {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 60px;
|
||||||
|
margin: auto;
|
||||||
|
border-radius: 100%;
|
||||||
|
background: var(--panel);
|
||||||
|
color: var(--fg);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--panelHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: var(--X2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.postButton {
|
||||||
|
composes: navButton;
|
||||||
|
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
|
||||||
|
color: var(--fgOnAccent);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navButtonIcon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navButtonIndicator {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
color: var(--indicator);
|
||||||
|
font-size: 16px;
|
||||||
|
animation: blink 1s infinite;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,31 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
|
<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
|
||||||
<section
|
<section
|
||||||
v-hotkey="keymap" class="dnpfarvg"
|
v-hotkey="keymap"
|
||||||
:class="{ paged: isMainColumn, naked, active, isStacked, draghover, dragging, dropready }"
|
:class="[$style.root, { [$style.paged]: isMainColumn, [$style.naked]: naked, [$style.active]: active, [$style.isStacked]: isStacked, [$style.draghover]: draghover, [$style.dragging]: dragging, [$style.dropready]: dropready }]"
|
||||||
@dragover.prevent.stop="onDragover"
|
@dragover.prevent.stop="onDragover"
|
||||||
@dragleave="onDragleave"
|
@dragleave="onDragleave"
|
||||||
@drop.prevent.stop="onDrop"
|
@drop.prevent.stop="onDrop"
|
||||||
>
|
>
|
||||||
<header
|
<header
|
||||||
:class="{ indicated }"
|
:class="[$style.header]"
|
||||||
draggable="true"
|
draggable="true"
|
||||||
@click="goTop"
|
@click="goTop"
|
||||||
@dragstart="onDragstart"
|
@dragstart="onDragstart"
|
||||||
@dragend="onDragend"
|
@dragend="onDragend"
|
||||||
@contextmenu.prevent.stop="onContextmenu"
|
@contextmenu.prevent.stop="onContextmenu"
|
||||||
>
|
>
|
||||||
<button v-if="isStacked && !isMainColumn" class="toggleActive _button" @click="toggleActive">
|
<button v-if="isStacked && !isMainColumn" :class="$style.toggleActive" class="_button" @click="toggleActive">
|
||||||
<template v-if="active"><i class="ti ti-chevron-up"></i></template>
|
<template v-if="active"><i class="ti ti-chevron-up"></i></template>
|
||||||
<template v-else><i class="ti ti-chevron-down"></i></template>
|
<template v-else><i class="ti ti-chevron-down"></i></template>
|
||||||
</button>
|
</button>
|
||||||
<div class="action">
|
<span :class="$style.title"><slot name="header"></slot></span>
|
||||||
<slot name="action"></slot>
|
<button v-tooltip="i18n.ts.settings" :class="$style.menu" class="_button" @click.stop="showSettingsMenu"><i class="ti ti-dots"></i></button>
|
||||||
</div>
|
|
||||||
<span class="header"><slot name="header"></slot></span>
|
|
||||||
<button v-tooltip="i18n.ts.settings" class="menu _button" @click.stop="showSettingsMenu"><i class="ti ti-dots"></i></button>
|
|
||||||
</header>
|
</header>
|
||||||
<div v-show="active" ref="body">
|
<div v-show="active" ref="body" :class="$style.body">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -46,12 +43,10 @@ const props = withDefaults(defineProps<{
|
||||||
column: Column;
|
column: Column;
|
||||||
isStacked?: boolean;
|
isStacked?: boolean;
|
||||||
naked?: boolean;
|
naked?: boolean;
|
||||||
indicated?: boolean;
|
|
||||||
menu?: MenuItem[];
|
menu?: MenuItem[];
|
||||||
}>(), {
|
}>(), {
|
||||||
isStacked: false,
|
isStacked: false,
|
||||||
naked: false,
|
naked: false,
|
||||||
indicated: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -245,8 +240,8 @@ function onDrop(ev) {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.dnpfarvg {
|
.root {
|
||||||
--root-margin: 10px;
|
--root-margin: 10px;
|
||||||
--deckColumnHeaderHeight: 40px;
|
--deckColumnHeaderHeight: 40px;
|
||||||
|
|
||||||
|
@ -292,10 +287,6 @@ function onDrop(ev) {
|
||||||
&:not(.active) {
|
&:not(.active) {
|
||||||
flex-basis: var(--deckColumnHeaderHeight);
|
flex-basis: var(--deckColumnHeaderHeight);
|
||||||
min-height: var(--deckColumnHeaderHeight);
|
min-height: var(--deckColumnHeaderHeight);
|
||||||
|
|
||||||
> header.indicated {
|
|
||||||
box-shadow: 4px 0px var(--accent) inset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.naked {
|
&.naked {
|
||||||
|
@ -303,97 +294,78 @@ function onDrop(ev) {
|
||||||
-webkit-backdrop-filter: var(--blur, blur(10px));
|
-webkit-backdrop-filter: var(--blur, blur(10px));
|
||||||
backdrop-filter: var(--blur, blur(10px));
|
backdrop-filter: var(--blur, blur(10px));
|
||||||
|
|
||||||
> header {
|
> .header {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
color: var(--fg);
|
||||||
> button {
|
|
||||||
color: var(--fg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.paged {
|
&.paged {
|
||||||
background: var(--bg) !important;
|
background: var(--bg) !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> header {
|
.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
line-height: var(--deckColumnHeaderHeight);
|
line-height: var(--deckColumnHeaderHeight);
|
||||||
height: var(--deckColumnHeaderHeight);
|
height: var(--deckColumnHeaderHeight);
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
color: var(--panelHeaderFg);
|
color: var(--panelHeaderFg);
|
||||||
background: var(--panelHeaderBg);
|
background: var(--panelHeaderBg);
|
||||||
box-shadow: 0 1px 0 0 var(--panelHeaderDivider);
|
box-shadow: 0 1px 0 0 var(--panelHeaderDivider);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&, * {
|
&, * {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
|
||||||
|
|
||||||
&.indicated {
|
|
||||||
box-shadow: 0 3px 0 0 var(--accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .header {
|
|
||||||
display: inline-block;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
> span:only-of-type {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .toggleActive,
|
|
||||||
> .action > ::v-deep(*),
|
|
||||||
> .menu {
|
|
||||||
z-index: 1;
|
|
||||||
width: var(--deckColumnHeaderHeight);
|
|
||||||
line-height: var(--deckColumnHeaderHeight);
|
|
||||||
color: var(--faceTextButton);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--faceTextButtonHover);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: var(--faceTextButtonActive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .toggleActive, > .action {
|
|
||||||
margin-left: -16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .action {
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .action:empty {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .menu {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: -16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
height: calc(100% - var(--deckColumnHeaderHeight));
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden; // Safari does not supports clip
|
|
||||||
overflow-x: clip;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
|
||||||
box-sizing: border-box;
|
|
||||||
container-type: inline-size;
|
|
||||||
background-color: var(--bg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: inline-block;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleActive,
|
||||||
|
.menu {
|
||||||
|
z-index: 1;
|
||||||
|
width: var(--deckColumnHeaderHeight);
|
||||||
|
line-height: var(--deckColumnHeaderHeight);
|
||||||
|
color: var(--faceTextButton);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--faceTextButtonHover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: var(--faceTextButtonActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggleActive {
|
||||||
|
margin-left: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
height: calc(100% - var(--deckColumnHeaderHeight));
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden; // Safari does not supports clip
|
||||||
|
overflow-x: clip;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
box-sizing: border-box;
|
||||||
|
container-type: inline-size;
|
||||||
|
background-color: var(--bg);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<XColumn :menu="menu" :column="column" :is-stacked="isStacked" :indicated="indicated" @change-active-state="onChangeActiveState" @parent-focus="$event => emit('parent-focus', $event)">
|
<XColumn :menu="menu" :column="column" :is-stacked="isStacked" @parent-focus="$event => emit('parent-focus', $event)">
|
||||||
<template #header>
|
<template #header>
|
||||||
<i v-if="column.tl === 'home'" class="ti ti-home"></i>
|
<i v-if="column.tl === 'home'" class="ti ti-home"></i>
|
||||||
<i v-else-if="column.tl === 'local'" class="ti ti-planet"></i>
|
<i v-else-if="column.tl === 'local'" class="ti ti-planet"></i>
|
||||||
|
@ -15,7 +15,7 @@
|
||||||
</p>
|
</p>
|
||||||
<p class="desc">{{ $t('disabled-timeline.description') }}</p>
|
<p class="desc">{{ $t('disabled-timeline.description') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<XTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl" @after="() => emit('loaded')" @queue="queueUpdated" @note="onNote"/>
|
<XTimeline v-else-if="column.tl" ref="timeline" :key="column.tl" :src="column.tl" @after="() => emit('loaded')"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -40,8 +40,6 @@ const emit = defineEmits<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let disabled = $ref(false);
|
let disabled = $ref(false);
|
||||||
let indicated = $ref(false);
|
|
||||||
let columnActive = $ref(true);
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.column.tl == null) {
|
if (props.column.tl == null) {
|
||||||
|
@ -77,26 +75,6 @@ async function setType() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function queueUpdated(q) {
|
|
||||||
if (columnActive) {
|
|
||||||
indicated = q !== 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onNote() {
|
|
||||||
if (!columnActive) {
|
|
||||||
indicated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onChangeActiveState(state) {
|
|
||||||
columnActive = state;
|
|
||||||
|
|
||||||
if (columnActive) {
|
|
||||||
indicated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const menu = [{
|
const menu = [{
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.timeline,
|
text: i18n.ts.timeline,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="dkgtipfy" :class="{ wallpaper }">
|
<div :class="[$style.root, { [$style.withWallpaper]: wallpaper }]">
|
||||||
<XSidebar v-if="!isMobile" class="sidebar"/>
|
<XSidebar v-if="!isMobile" :class="$style.sidebar"/>
|
||||||
|
|
||||||
<MkStickyContainer class="contents">
|
<MkStickyContainer :class="$style.contents">
|
||||||
<template #header><XStatusBars :class="$style.statusbars"/></template>
|
<template #header><XStatusBars :class="$style.statusbars"/></template>
|
||||||
<main style="min-width: 0;" :style="{ background: pageMetadata?.value?.bg }" @contextmenu.stop="onContextmenu">
|
<main style="min-width: 0;" :style="{ background: pageMetadata?.value?.bg }" @contextmenu.stop="onContextmenu">
|
||||||
<div :class="$style.content" style="container-type: inline-size;">
|
<div :class="$style.content" style="container-type: inline-size;">
|
||||||
|
@ -12,44 +12,71 @@
|
||||||
</main>
|
</main>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
|
|
||||||
<div v-if="isDesktop" ref="widgetsEl" class="widgets">
|
<div v-if="isDesktop" ref="widgetsEl" :class="$style.widgets">
|
||||||
<XWidgets @mounted="attachSticky"/>
|
<XWidgets :margin-top="'var(--margin)'" @mounted="attachSticky"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button v-if="!isDesktop && !isMobile" class="widgetButton _button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button>
|
<button v-if="!isDesktop && !isMobile" :class="$style.widgetButton" class="_button" @click="widgetsShowing = true"><i class="ti ti-apps"></i></button>
|
||||||
|
|
||||||
<div v-if="isMobile" class="buttons">
|
<div v-if="isMobile" :class="$style.nav">
|
||||||
<button class="button nav _button" @click="drawerMenuShowing = true"><i class="icon ti ti-menu-2"></i><span v-if="menuIndicated" class="indicator"><i class="_indicatorCircle"></i></span></button>
|
<button :class="$style.navButton" class="_button" @click="drawerMenuShowing = true"><i :class="$style.navButtonIcon" class="ti ti-menu-2"></i><span v-if="menuIndicated" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
|
||||||
<button class="button home _button" @click="mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')"><i class="icon ti ti-home"></i></button>
|
<button :class="$style.navButton" class="_button" @click="mainRouter.currentRoute.value.name === 'index' ? top() : mainRouter.push('/')"><i :class="$style.navButtonIcon" class="ti ti-home"></i></button>
|
||||||
<button class="button notifications _button" @click="mainRouter.push('/my/notifications')"><i class="icon ti ti-bell"></i><span v-if="$i?.hasUnreadNotification" class="indicator"><i class="_indicatorCircle"></i></span></button>
|
<button :class="$style.navButton" class="_button" @click="mainRouter.push('/my/notifications')"><i :class="$style.navButtonIcon" class="ti ti-bell"></i><span v-if="$i?.hasUnreadNotification" :class="$style.navButtonIndicator"><i class="_indicatorCircle"></i></span></button>
|
||||||
<button class="button widget _button" @click="widgetsShowing = true"><i class="icon ti ti-apps"></i></button>
|
<button :class="$style.navButton" class="_button" @click="widgetsShowing = true"><i :class="$style.navButtonIcon" class="ti ti-apps"></i></button>
|
||||||
<button class="button post _button" @click="os.post()"><i class="icon ti ti-pencil"></i></button>
|
<button :class="$style.postButton" class="_button" @click="os.post()"><i :class="$style.navButtonIcon" class="ti ti-pencil"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Transition :name="$store.state.animation ? 'menuDrawer-back' : ''">
|
<Transition
|
||||||
|
:enter-active-class="$store.state.animation ? $style.transition_menuDrawerBg_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="drawerMenuShowing"
|
v-if="drawerMenuShowing"
|
||||||
class="menuDrawer-back _modalBg"
|
:class="$style.menuDrawerBg"
|
||||||
|
class="_modalBg"
|
||||||
@click="drawerMenuShowing = false"
|
@click="drawerMenuShowing = false"
|
||||||
@touchstart.passive="drawerMenuShowing = false"
|
@touchstart.passive="drawerMenuShowing = false"
|
||||||
></div>
|
></div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<Transition :name="$store.state.animation ? 'menuDrawer' : ''">
|
<Transition
|
||||||
<XDrawerMenu v-if="drawerMenuShowing" class="menuDrawer"/>
|
:enter-active-class="$store.state.animation ? $style.transition_menuDrawer_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_menuDrawer_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_menuDrawer_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_menuDrawer_leaveTo : ''"
|
||||||
|
>
|
||||||
|
<div v-if="drawerMenuShowing" :class="$style.menuDrawer">
|
||||||
|
<XDrawerMenu/>
|
||||||
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<Transition :name="$store.state.animation ? 'widgetsDrawer-back' : ''">
|
<Transition
|
||||||
|
:enter-active-class="$store.state.animation ? $style.transition_widgetsDrawerBg_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_widgetsDrawerBg_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_widgetsDrawerBg_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_widgetsDrawerBg_leaveTo : ''"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-if="widgetsShowing"
|
v-if="widgetsShowing"
|
||||||
class="widgetsDrawer-back _modalBg"
|
:class="$style.widgetsDrawerBg"
|
||||||
|
class="_modalBg"
|
||||||
@click="widgetsShowing = false"
|
@click="widgetsShowing = false"
|
||||||
@touchstart.passive="widgetsShowing = false"
|
@touchstart.passive="widgetsShowing = false"
|
||||||
></div>
|
></div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<Transition :name="$store.state.animation ? 'widgetsDrawer' : ''">
|
<Transition
|
||||||
<XWidgets v-if="widgetsShowing" class="widgetsDrawer"/>
|
:enter-active-class="$store.state.animation ? $style.transition_widgetsDrawer_enterActive : ''"
|
||||||
|
:leave-active-class="$store.state.animation ? $style.transition_widgetsDrawer_leaveActive : ''"
|
||||||
|
:enter-from-class="$store.state.animation ? $style.transition_widgetsDrawer_enterFrom : ''"
|
||||||
|
:leave-to-class="$store.state.animation ? $style.transition_widgetsDrawer_leaveTo : ''"
|
||||||
|
>
|
||||||
|
<div v-if="widgetsShowing" :class="$style.widgetsDrawer">
|
||||||
|
<button class="_button" :class="$style.widgetsCloseButton" @click="widgetsShowing = false"><i class="ti ti-x"></i></button>
|
||||||
|
<XWidgets/>
|
||||||
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<XCommon/>
|
<XCommon/>
|
||||||
|
@ -174,195 +201,210 @@ function top() {
|
||||||
const wallpaper = miLocalStorage.getItem('wallpaper') != null;
|
const wallpaper = miLocalStorage.getItem('wallpaper') != null;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.widgetsDrawer-enter-active,
|
$ui-font-size: 1em; // TODO: どこかに集約したい
|
||||||
.widgetsDrawer-leave-active {
|
$widgets-hide-threshold: 1090px;
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0);
|
|
||||||
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
|
||||||
}
|
|
||||||
.widgetsDrawer-enter-from,
|
|
||||||
.widgetsDrawer-leave-active {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(240px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.widgetsDrawer-back-enter-active,
|
.transition_menuDrawerBg_enterActive,
|
||||||
.widgetsDrawer-back-leave-active {
|
.transition_menuDrawerBg_leaveActive {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
}
|
}
|
||||||
.widgetsDrawer-back-enter-from,
|
.transition_menuDrawerBg_enterFrom,
|
||||||
.widgetsDrawer-back-leave-active {
|
.transition_menuDrawerBg_leaveTo {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuDrawer-enter-active,
|
.transition_menuDrawer_enterActive,
|
||||||
.menuDrawer-leave-active {
|
.transition_menuDrawer_leaveActive {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
}
|
}
|
||||||
.menuDrawer-enter-from,
|
.transition_menuDrawer_enterFrom,
|
||||||
.menuDrawer-leave-active {
|
.transition_menuDrawer_leaveTo {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-240px);
|
transform: translateX(-240px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuDrawer-back-enter-active,
|
.transition_widgetsDrawerBg_enterActive,
|
||||||
.menuDrawer-back-leave-active {
|
.transition_widgetsDrawerBg_leaveActive {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
}
|
}
|
||||||
.menuDrawer-back-enter-from,
|
.transition_widgetsDrawerBg_enterFrom,
|
||||||
.menuDrawer-back-leave-active {
|
.transition_widgetsDrawerBg_leaveTo {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dkgtipfy {
|
.transition_widgetsDrawer_enterActive,
|
||||||
$ui-font-size: 1em; // TODO: どこかに集約したい
|
.transition_widgetsDrawer_leaveActive {
|
||||||
$widgets-hide-threshold: 1090px;
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
.transition_widgetsDrawer_enterFrom,
|
||||||
|
.transition_widgetsDrawer_leaveTo {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(240px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.root {
|
||||||
min-height: 100dvh;
|
min-height: 100dvh;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
&.wallpaper {
|
.withWallpaper {
|
||||||
background: var(--wallpaperOverlay);
|
background: var(--wallpaperOverlay);
|
||||||
//backdrop-filter: var(--blur, blur(4px));
|
//backdrop-filter: var(--blur, blur(4px));
|
||||||
}
|
}
|
||||||
|
|
||||||
> .sidebar {
|
.sidebar {
|
||||||
border-right: solid 0.5px var(--divider);
|
border-right: solid 0.5px var(--divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .contents {
|
.contents {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .widgets {
|
.widgets {
|
||||||
padding: 0 var(--margin);
|
padding: 0 var(--margin);
|
||||||
border-left: solid 0.5px var(--divider);
|
border-left: solid 0.5px var(--divider);
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
|
|
||||||
@media (max-width: $widgets-hide-threshold) {
|
@media (max-width: $widgets-hide-threshold) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .widgetButton {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1000;
|
|
||||||
bottom: 32px;
|
|
||||||
right: 32px;
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
border-radius: 100%;
|
|
||||||
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
|
|
||||||
font-size: 22px;
|
|
||||||
background: var(--panel);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .widgetsDrawer-back {
|
|
||||||
z-index: 1001;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .widgetsDrawer {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
height: 100dvh;
|
|
||||||
padding: var(--margin) !important;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: auto;
|
|
||||||
overscroll-behavior: contain;
|
|
||||||
background: var(--bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .buttons {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 1000;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 12px 12px max(12px, env(safe-area-inset-bottom, 0px)) 12px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
|
||||||
grid-gap: 8px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-backdrop-filter: var(--blur, blur(32px));
|
|
||||||
backdrop-filter: var(--blur, blur(32px));
|
|
||||||
background-color: var(--header);
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
|
|
||||||
> .button {
|
|
||||||
position: relative;
|
|
||||||
padding: 0;
|
|
||||||
aspect-ratio: 1;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 60px;
|
|
||||||
margin: auto;
|
|
||||||
border-radius: 100%;
|
|
||||||
background: var(--panel);
|
|
||||||
color: var(--fg);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--X2);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .indicator {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
color: var(--indicator);
|
|
||||||
font-size: 16px;
|
|
||||||
animation: blink 1s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .icon {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
> .icon {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.post {
|
|
||||||
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
|
|
||||||
color: var(--fgOnAccent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .menuDrawer-back {
|
|
||||||
z-index: 1001;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .menuDrawer {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
height: 100dvh;
|
|
||||||
width: 240px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
contain: strict;
|
|
||||||
overflow: auto;
|
|
||||||
overscroll-behavior: contain;
|
|
||||||
background: var(--navBg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
|
||||||
<style lang="scss" module>
|
.widgetButton {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
bottom: 32px;
|
||||||
|
right: 32px;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 100%;
|
||||||
|
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);
|
||||||
|
font-size: 22px;
|
||||||
|
background: var(--panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
.widgetsDrawerBg {
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widgetsDrawer {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1001;
|
||||||
|
height: 100dvh;
|
||||||
|
padding: var(--margin) !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
background: var(--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.widgetsCloseButton {
|
||||||
|
padding: 8px;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 370px) {
|
||||||
|
.widgetsCloseButton {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 12px 12px max(12px, env(safe-area-inset-bottom, 0px)) 12px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
grid-gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
-webkit-backdrop-filter: var(--blur, blur(32px));
|
||||||
|
backdrop-filter: var(--blur, blur(32px));
|
||||||
|
background-color: var(--header);
|
||||||
|
border-top: solid 0.5px var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navButton {
|
||||||
|
position: relative;
|
||||||
|
padding: 0;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 60px;
|
||||||
|
margin: auto;
|
||||||
|
border-radius: 100%;
|
||||||
|
background: var(--panel);
|
||||||
|
color: var(--fg);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--panelHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: var(--X2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.postButton {
|
||||||
|
composes: navButton;
|
||||||
|
background: linear-gradient(90deg, var(--buttonGradateA), var(--buttonGradateB));
|
||||||
|
color: var(--fgOnAccent);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: linear-gradient(90deg, var(--X8), var(--X8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.navButtonIcon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navButtonIndicator {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
color: var(--indicator);
|
||||||
|
font-size: 16px;
|
||||||
|
animation: blink 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuDrawerBg {
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menuDrawer {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1001;
|
||||||
|
height: 100dvh;
|
||||||
|
width: 240px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
contain: strict;
|
||||||
|
overflow: auto;
|
||||||
|
overscroll-behavior: contain;
|
||||||
|
background: var(--navBg);
|
||||||
|
}
|
||||||
|
|
||||||
.statusbars {
|
.statusbars {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -370,12 +412,6 @@ const wallpaper = miLocalStorage.getItem('wallpaper') != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spacer {
|
.spacer {
|
||||||
$widgets-hide-threshold: 1090px;
|
height: calc(var(--minBottomSpacing));
|
||||||
|
|
||||||
height: calc(env(safe-area-inset-bottom, 0px) + 96px);
|
|
||||||
|
|
||||||
@media (min-width: ($widgets-hide-threshold + 1px)) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="efzpzdvf" :class="{ universal: !classic, classic }">
|
<div :class="$style.root" :style="{ paddingTop: marginTop }">
|
||||||
<XWidgets :edit="editMode" :widgets="widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
|
<XWidgets :class="$style.widgets" :edit="editMode" :widgets="widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
|
||||||
|
|
||||||
<button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button>
|
<button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="ti ti-check"></i> {{ i18n.ts.editWidgetsExit }}</button>
|
||||||
<button v-else class="_textButton mk-widget-edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button>
|
<button v-else class="_textButton mk-widget-edit" style="font-size: 0.9em;" @click="editMode = true"><i class="ti ti-pencil"></i> {{ i18n.ts.editWidgets }}</button>
|
||||||
|
@ -21,10 +21,10 @@ const props = withDefaults(defineProps<{
|
||||||
// left = place: leftだけを表示
|
// left = place: leftだけを表示
|
||||||
// right = rightとnullを表示
|
// right = rightとnullを表示
|
||||||
place?: 'left' | null | 'right';
|
place?: 'left' | null | 'right';
|
||||||
classic?: boolean;
|
marginTop?: string;
|
||||||
}>(), {
|
}>(), {
|
||||||
place: null,
|
place: null,
|
||||||
classic: false,
|
marginTop: '0',
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -81,31 +81,14 @@ function updateWidgets(thisWidgets) {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.efzpzdvf {
|
.root {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
height: min-content;
|
height: min-content;
|
||||||
min-height: 100vh;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
&.universal {
|
.widgets {
|
||||||
padding-top: var(--margin);
|
width: 300px;
|
||||||
|
|
||||||
> * {
|
|
||||||
margin: var(--margin) 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
width: 300px;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .add {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
|
||||||
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
||||||
import XCalendar from './activity.calendar.vue';
|
import XCalendar from './WidgetActivity.calendar.vue';
|
||||||
import XChart from './activity.chart.vue';
|
import XChart from './WidgetActivity.chart.vue';
|
||||||
import { GetFormResultType } from '@/scripts/form';
|
import { GetFormResultType } from '@/scripts/form';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import MkContainer from '@/components/MkContainer.vue';
|
import MkContainer from '@/components/MkContainer.vue';
|
|
@ -0,0 +1,94 @@
|
||||||
|
<template>
|
||||||
|
<div class="_panel">
|
||||||
|
<div :class="$style.container" :style="{ backgroundImage: $instance.bannerUrl ? `url(${ $instance.bannerUrl })` : null }">
|
||||||
|
<div :class="$style.iconContainer">
|
||||||
|
<img :src="$instance.iconUrl ?? $instance.faviconUrl ?? '/favicon.ico'" alt="" :class="$style.icon"/>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.bodyContainer">
|
||||||
|
<div :class="$style.body">
|
||||||
|
<MkA :class="$style.name" to="/about" behavior="window">{{ $instance.name }}</MkA>
|
||||||
|
<div :class="$style.host">{{ host }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
|
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
||||||
|
import { GetFormResultType } from '@/scripts/form';
|
||||||
|
import { host } from '@/config';
|
||||||
|
|
||||||
|
const name = 'instanceInfo';
|
||||||
|
|
||||||
|
const widgetPropsDef = {
|
||||||
|
};
|
||||||
|
|
||||||
|
type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
|
||||||
|
|
||||||
|
// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない
|
||||||
|
//const props = defineProps<WidgetComponentProps<WidgetProps>>();
|
||||||
|
//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
|
||||||
|
const props = defineProps<{ widget?: Widget<WidgetProps>; }>();
|
||||||
|
const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>();
|
||||||
|
|
||||||
|
const { widgetProps, configure } = useWidgetPropsManager(name,
|
||||||
|
widgetPropsDef,
|
||||||
|
props,
|
||||||
|
emit,
|
||||||
|
);
|
||||||
|
|
||||||
|
defineExpose<WidgetComponentExpose>({
|
||||||
|
name,
|
||||||
|
configure,
|
||||||
|
id: props.widget ? props.widget.id : null,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconContainer {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: solid 3px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bodyContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0 16px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: #fff;
|
||||||
|
filter: drop-shadow(0 0 4px #000);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.host {
|
||||||
|
color: #fff;
|
||||||
|
filter: drop-shadow(0 0 4px #000);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,96 @@
|
||||||
|
<template>
|
||||||
|
<div class="_panel">
|
||||||
|
<div :class="$style.container" :style="{ backgroundImage: $i.bannerUrl ? `url(${ $i.bannerUrl })` : null }">
|
||||||
|
<div :class="$style.avatarContainer">
|
||||||
|
<MkAvatar :class="$style.avatar" :user="$i" :disable-link="true" :disable-preview="true"/>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.bodyContainer">
|
||||||
|
<div :class="$style.body">
|
||||||
|
<MkA :class="$style.name" :to="userPage($i)">
|
||||||
|
<MkUserName :user="$i"/>
|
||||||
|
</MkA>
|
||||||
|
<div :class="$style.username"><MkAcct :user="$i" detail/></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
|
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
|
||||||
|
import { GetFormResultType } from '@/scripts/form';
|
||||||
|
import { $i } from '@/account';
|
||||||
|
import { userPage } from '@/filters/user';
|
||||||
|
|
||||||
|
const name = 'profile';
|
||||||
|
|
||||||
|
const widgetPropsDef = {
|
||||||
|
};
|
||||||
|
|
||||||
|
type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
|
||||||
|
|
||||||
|
// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない
|
||||||
|
//const props = defineProps<WidgetComponentProps<WidgetProps>>();
|
||||||
|
//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
|
||||||
|
const props = defineProps<{ widget?: Widget<WidgetProps>; }>();
|
||||||
|
const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>();
|
||||||
|
|
||||||
|
const { widgetProps, configure } = useWidgetPropsManager(name,
|
||||||
|
widgetPropsDef,
|
||||||
|
props,
|
||||||
|
emit,
|
||||||
|
);
|
||||||
|
|
||||||
|
defineExpose<WidgetComponentExpose>({
|
||||||
|
name,
|
||||||
|
configure,
|
||||||
|
id: props.widget ? props.widget.id : null,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatarContainer {
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
display: inline-block;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: solid 3px #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bodyContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
padding: 0 16px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: #fff;
|
||||||
|
filter: drop-shadow(0 0 4px #000);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.username {
|
||||||
|
color: #fff;
|
||||||
|
filter: drop-shadow(0 0 4px #000);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -108,10 +108,7 @@ const tick = () => {
|
||||||
window.fetch(fetchEndpoint.value, {})
|
window.fetch(fetchEndpoint.value, {})
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(feed => {
|
.then(feed => {
|
||||||
if (widgetProps.shuffle) {
|
rawItems.value = feed.items ?? [];
|
||||||
shuffle(feed.items);
|
|
||||||
}
|
|
||||||
rawItems.value = feed.items;
|
|
||||||
fetching.value = false;
|
fetching.value = false;
|
||||||
key++;
|
key++;
|
||||||
});
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue