diff --git a/README.md b/README.md
index 0b02e0cb..bcac27c9 100644
--- a/README.md
+++ b/README.md
@@ -32,8 +32,15 @@
- emojis are sourced from discord's list of emojis
- emojis are now sorted by category (like on every other emoji picker) instead of alphabetically
- script to get new emojis is included for future unicode versions
+- cat stuff!!
+ - toggles for:
+ - showing "cat" badge on user profiles
+ - showing cat ears behind users' avatars
+ - "nyaize"-ing posts from authors with "Speak as Cat" enabled
+ - this requires [a backend patch](https://git.notfire.cc/notfire/iceshrimp-patches/src/branch/main/0007-cat-fields-in-akko-api.patch)
- add toggle for showing post edit notifications
- add support for accepted follow request notifications
+ - this requires [a backend patch](https://git.notfire.cc/notfire/iceshrimp-patches/src/branch/main/0005-previews-in-mastoapi.patch)
- add option to prevent page from getting pushed when making a new post with streaming api enabled (similar to 3rd "for unreads" option)
- add link on user card to open profiles in iceshrimp-fe
- add option to open conversation view by clicking empty space in posts
@@ -42,6 +49,11 @@
- add a script to download ruffle for flash support (requires python3 and requests library)
- download by entering `tools/` and running `python3 download_ruffle.py`
+### also of note for anyone running this fork
+- aside from the stuff mentioned above, the following features will require patches to work:
+ - mfm ([patch](https://git.notfire.cc/notfire/iceshrimp-patches/src/branch/main/0004-mfm-in-mastoapi.patch))
+ - previewing posts ([patch](https://git.notfire.cc/notfire/iceshrimp-patches/src/branch/main/0005-previews-in-mastoapi.patch))
+
---
# Akkoma-FE
diff --git a/package.json b/package.json
index 5f8574dd..f087fb51 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
"cropperjs": "^1.6.2",
"diff": "^5.2.0",
"escape-html": "^1.0.3",
+ "fast-average-color": "^9.5.0",
"iso-639-1": "^2.1.15",
"js-cookie": "^3.0.1",
"localforage": "^1.10.0",
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 90bcdab3..7af0458d 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -180,6 +180,7 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('alwaysShowSubjectInput')
copyInstanceOption('showFeaturesPanel')
copyInstanceOption('hideSitename')
+ copyInstanceOption('showCatFields')
copyInstanceOption('renderMisskeyMarkdown')
copyInstanceOption('sidebarRight')
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index a829b0bf..3ce90bd1 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -135,6 +135,9 @@ const GeneralTab = {
this.$store.dispatch('setOption', { name: 'postLanguage', value: val })
}
},
+ catOptsAvail: {
+ get: function () { return this.$store.getters.mergedConfig.showCatFields }
+ },
...SharedComputedObject()
},
methods: {
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index dc64d348..b6c7e626 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -319,6 +319,35 @@
{{ $t('settings.search_pagination_limit') }}
+
+ {{ $t('settings.cat_settings') }}
+
+
+
+ {{ $t('settings.show_is_cat_on_user_card') }}
+
+
+
+
+ {{ $t('settings.show_cat_ears') }}
+
+
+
+
+ {{ $t('settings.nyaize_posts') }}
+
+
{{ $t('settings.columns') }}
diff --git a/src/components/status_body/status_body.js b/src/components/status_body/status_body.js
index 7ff6c3aa..2a1cbaed 100644
--- a/src/components/status_body/status_body.js
+++ b/src/components/status_body/status_body.js
@@ -86,6 +86,9 @@ const StatusContent = {
translationLanguages () {
return (this.$store.state.instance.supportedTranslationLanguages.source || []).map(lang => ({ key: lang.code, value: lang.code, label: lang.name }))
},
+ canSpeakAsCat () {
+ return (this.$store.getters.mergedConfig.nyaizePosts && this.status.user.speak_as_cat)
+ },
...mapGetters(['mergedConfig'])
},
components: {
@@ -140,6 +143,16 @@ const StatusContent = {
this.$store.dispatch(
'translateStatus', { id: this.status.id, language: translateTo, from: this.translateFrom }
).finally(() => { this.translating = false })
+ },
+ speakAsCat () {
+ // taken from https://github.com/misskey-dev/misskey/blob/develop/packages/misskey-js/src/nyaize.ts
+ const enRegex1 = /(?<=n)a/gi
+ const enRegex2 = /(?<=morn)ing/gi
+ const enRegex3 = /(?<=every)one/gi
+ return this.status.text
+ .replace(enRegex1, x => x === 'A' ? 'YA' : 'ya')
+ .replace(enRegex2, x => x === 'ING' ? 'YAN' : 'yan')
+ .replace(enRegex3, x => x === 'ONE' ? 'NYAN' : 'nyan')
}
}
}
diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue
index 068c6c1b..1bc48909 100644
--- a/src/components/status_body/status_body.vue
+++ b/src/components/status_body/status_body.vue
@@ -48,7 +48,7 @@
{
+ this.earsColor = fac.getColor(img).hex;
+ this.earsReady = true;
+ }
+ }
+ }
+ }
}
}
diff --git a/src/components/user_avatar/user_avatar.vue b/src/components/user_avatar/user_avatar.vue
index e64b54df..4bddd55b 100644
--- a/src/components/user_avatar/user_avatar.vue
+++ b/src/components/user_avatar/user_avatar.vue
@@ -3,6 +3,14 @@
class="Avatar"
:class="{ '-compact': compact }"
>
+
+
@import '../../_variables.scss';
+/* ears ripped from https://github.com/ihateblueb/aster/blob/main/packages/frontend/src/lib/components/Avatar.svelte */
.Avatar {
--_avatarShadowBox: var(--avatarStatusShadow);
--_avatarShadowFilter: var(--avatarStatusShadowFilter);
@@ -40,6 +50,17 @@
width: 48px;
height: 48px;
+ &:hover {
+ .ears {
+ .earLeft {
+ animation: earwiggleleft 1s infinite;
+ }
+ .earRight {
+ animation: earwiggleright 1s infinite;
+ }
+ }
+ }
+
&.-compact {
width: 32px;
height: 32px;
@@ -90,5 +111,116 @@
border-radius: var(--tooltipRadius);
}
+ .ears {
+ contain: strict;
+ position: absolute;
+ z-index: 0;
+ display: flex;
+
+ top: -50%;
+ left: -50%;
+ width: 100%;
+ height: 100%;
+ padding: 50%;
+
+ pointer-events: none;
+
+ .earLeft,
+ .earRight {
+ contain: strict;
+ display: inline-block;
+ height: 50%;
+ width: 50%;
+ background: currentColor;
+
+ &::after {
+ contain: strict;
+ content: '';
+ display: block;
+ width: 60%;
+ height: 60%;
+ margin: 20%;
+ background: #df548f;
+ }
+ }
+
+ .earLeft {
+ transform: rotate(37.5deg) skew(30deg);
+
+ &,
+ &::after {
+ border-radius: 25% 75% 75%;
+ }
+ }
+
+ .earRight {
+ transform: rotate(-37.5deg) skew(-30deg);
+
+ &,
+ &::after {
+ border-radius: 75% 25% 75% 75%;
+ }
+ }
+ }
+
+ @keyframes earwiggleleft {
+ from {
+ transform: rotate(37.6deg) skew(30deg);
+ }
+ 25% {
+ transform: rotate(10deg) skew(30deg);
+ }
+ 50% {
+ transform: rotate(20deg) skew(30deg);
+ }
+ 75% {
+ transform: rotate(0deg) skew(30deg);
+ }
+ to {
+ transform: rotate(37.6deg) skew(30deg);
+ }
+ }
+
+ @keyframes earwiggleright {
+ from {
+ transform: rotate(-37.6deg) skew(-30deg);
+ }
+ 30% {
+ transform: rotate(-10deg) skew(-30deg);
+ }
+ 55% {
+ transform: rotate(-20deg) skew(-30deg);
+ }
+ 75% {
+ transform: rotate(0deg) skew(-30deg);
+ }
+ to {
+ transform: rotate(-37.6deg) skew(-30deg);
+ }
+ }
+
+ @keyframes eartightleft {
+ from {
+ transform: rotate(37.6deg) skew(30deg);
+ }
+ 50% {
+ transform: rotate(37.4deg) skew(30deg);
+ }
+ to {
+ transform: rotate(37.6deg) skew(30deg);
+ }
+ }
+
+ @keyframes eartightright {
+ from {
+ transform: rotate(-37.6deg) skew(-30deg);
+ }
+ 50% {
+ transform: rotate(-37.4deg) skew(-30deg);
+ }
+ to {
+ transform: rotate(-37.6deg) skew(-30deg);
+ }
+ }
}
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index dc876522..cfc9eac6 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -54,7 +54,7 @@
>
@{{ user.screen_name_ui }}
-
+
{{ $t('user_card.bot') }}
+
+ {{ $t('user_card.is_cat') }}
+
{
output.friends_count = data.following_count
output.bot = data.bot
+ output.is_cat = typeof data.is_cat !== 'undefined' ? data.is_cat : false
+ output.speak_as_cat = typeof data.speak_as_cat !== 'undefined' ? data.speak_as_cat : false
output.accepts_direct_messages_from = data.accepts_direct_messages_from
output.follow_requests_count = data.follow_requests_count
if (data.akkoma) {
diff --git a/yarn.lock b/yarn.lock
index 6abf579f..17ef3fbf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3998,6 +3998,11 @@ extract-zip@^2.0.1:
optionalDependencies:
"@types/yauzl" "^2.9.1"
+fast-average-color@^9.5.0:
+ version "9.5.0"
+ resolved "https://registry.yarnpkg.com/fast-average-color/-/fast-average-color-9.5.0.tgz"
+ integrity sha512-nC6x2YIlJ9xxgkMFMd1BNoM1ctMjNoRKfRliPmiEWW3S6rLTHiQcy9g3pt/xiKv/D0NAAkhb9VyV+WJFvTqMGg==
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"