diff --git a/CALCKEY.md b/CALCKEY.md
index b05d4064d..7ab6f1f94 100644
--- a/CALCKEY.md
+++ b/CALCKEY.md
@@ -57,7 +57,6 @@
- Quotes have solid border
- Reply limit bug fixed
- Make showing the update popup optional
-- Obliteration of Ai-chan
- [Make showing ads optional](https://github.com/misskey-dev/misskey/pull/8996)
- [OAuth bearer token authentication](https://github.com/misskey-dev/misskey/pull/9021)
- [Styled Repair Tools](https://github.com/misskey-dev/misskey/pull/8956)
diff --git a/cypress/e2e/widgets.cy.js b/cypress/e2e/widgets.cy.js
index db35a60b5..56ad95ee9 100644
--- a/cypress/e2e/widgets.cy.js
+++ b/cypress/e2e/widgets.cy.js
@@ -61,4 +61,5 @@ describe('After user signed in', () => {
buildWidgetTest('jobQueue');
buildWidgetTest('button');
buildWidgetTest('aiscript');
+ buildWidgetTest('aichan');
});
diff --git a/locales/en-US.yml b/locales/en-US.yml
index f64a7c20d..212e49e4e 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1,6 +1,6 @@
---
_lang_: "English"
-headlineMisskey: "An open source, decentralized social media platform that's free forever! 🚀"
+headlineMisskey: "A network connected by notes"
introMisskey: "Welcome! Calckey is an open source, decentralized microblogging service.\nCreate \"notes\" to share your thoughts with everyone around you. 📡\nWith \"reactions\", you can also quickly express your feelings about everyone's notes. 👍\nLet's explore a new world! 🚀"
monthAndDay: "{month}/{day}"
search: "Search"
diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts
index 218d861e5..1c8fe9785 100644
--- a/packages/backend/src/models/schema/user.ts
+++ b/packages/backend/src/models/schema/user.ts
@@ -15,7 +15,7 @@ export const packedUserLiteSchema = {
username: {
type: 'string',
nullable: false, optional: false,
- example: 'calc',
+ example: 'ai',
},
host: {
type: 'string',
diff --git a/packages/backend/src/server/api/openapi/errors.ts b/packages/backend/src/server/api/openapi/errors.ts
index e632b4a0f..d7f791c6d 100644
--- a/packages/backend/src/server/api/openapi/errors.ts
+++ b/packages/backend/src/server/api/openapi/errors.ts
@@ -34,11 +34,11 @@ export const errors = {
},
},
'418': {
- 'I_AM_CALC': {
+ 'I_AM_AI': {
value: {
error: {
- message: 'You sent a request to Calc, Calckey\'s resident stoner furry, instead of the server.',
- code: 'I_AM_CALC',
+ message: 'You sent a request to Ai-chan, Misskey\'s showgirl, instead of the server.',
+ code: 'I_AM_AI',
id: '60c46cd1-f23a-46b1-bebe-5d2b73951a84',
},
},
diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts
index 00769d100..5c48373d5 100644
--- a/packages/backend/src/server/api/openapi/gen-spec.ts
+++ b/packages/backend/src/server/api/openapi/gen-spec.ts
@@ -156,7 +156,7 @@ export function genOpenapiSpec() {
},
},
'418': {
- description: 'I\'m Calc',
+ description: 'I\'m Ai',
content: {
'application/json': {
schema: {
diff --git a/packages/client/src/components/sample.vue b/packages/client/src/components/sample.vue
index 48c7fe844..fddadd6e9 100644
--- a/packages/client/src/components/sample.vue
+++ b/packages/client/src/components/sample.vue
@@ -59,7 +59,7 @@ export default defineComponent({
async openDialog() {
os.alert({
type: 'warning',
- title: 'Oh my Calc',
+ title: 'Oh my Aichan',
text: 'Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
});
},
diff --git a/packages/client/src/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue
index 22b27fad0..021f19b12 100644
--- a/packages/client/src/pages/settings/general.vue
+++ b/packages/client/src/pages/settings/general.vue
@@ -57,6 +57,7 @@
{{ i18n.ts.disableDrawer }}
{{ i18n.ts.showUpdates }}
+ {{ i18n.ts.aiChanMode }}
{{ i18n.ts.fontSize }}
@@ -145,6 +146,7 @@ const enterSendsMessage = computed(defaultStore.makeGetterSetter('enterSendsMess
const useReactionPickerForContextMenu = computed(defaultStore.makeGetterSetter('useReactionPickerForContextMenu'));
const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars'));
const showUpdates = computed(defaultStore.makeGetterSetter('showUpdates'));
+const aiChanMode = computed(defaultStore.makeGetterSetter('aiChanMode'));
watch(lang, () => {
localStorage.setItem('lang', lang.value as string);
@@ -173,6 +175,7 @@ watch([
useSystemFont,
enableInfiniteScroll,
squareAvatars,
+ aiChanMode,
showGapBetweenNotesInTimeline,
instanceTicker,
overridedDeviceKind,
diff --git a/packages/client/src/pages/settings/preferences-backups.vue b/packages/client/src/pages/settings/preferences-backups.vue
index b3aad708d..c7b4ee416 100644
--- a/packages/client/src/pages/settings/preferences-backups.vue
+++ b/packages/client/src/pages/settings/preferences-backups.vue
@@ -84,6 +84,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'squareAvatars',
'numberOfPageCache',
'showUpdates',
+ 'aiChanMode',
];
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
'lightTheme',
diff --git a/packages/client/src/store.ts b/packages/client/src/store.ts
index 1f141b2c1..3b95e6531 100644
--- a/packages/client/src/store.ts
+++ b/packages/client/src/store.ts
@@ -247,6 +247,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: 5,
},
+ aiChanMode: {
+ where: 'device',
+ default: false,
+ },
enterSendsMessage: {
where: 'device',
default: true,
diff --git a/packages/client/src/ui/classic.vue b/packages/client/src/ui/classic.vue
index 3c2ca8e5d..c42407f5b 100644
--- a/packages/client/src/ui/classic.vue
+++ b/packages/client/src/ui/classic.vue
@@ -34,6 +34,8 @@
+
+
@@ -144,6 +146,28 @@ onMounted(() => {
window.addEventListener('resize', () => {
isDesktop = (window.innerWidth >= DESKTOP_THRESHOLD);
}, { passive: true });
+
+ if (defaultStore.state.aiChanMode) {
+ const iframeRect = live2d.getBoundingClientRect();
+ window.addEventListener('mousemove', ev => {
+ live2d.contentWindow.postMessage({
+ type: 'moveCursor',
+ body: {
+ x: ev.clientX - iframeRect.left,
+ y: ev.clientY - iframeRect.top,
+ },
+ }, '*');
+ }, { passive: true });
+ window.addEventListener('touchmove', ev => {
+ live2d.contentWindow.postMessage({
+ type: 'moveCursor',
+ body: {
+ x: ev.touches[0].clientX - iframeRect.left,
+ y: ev.touches[0].clientY - iframeRect.top,
+ },
+ }, '*');
+ }, { passive: true });
+ }
});
diff --git a/packages/client/src/widgets/aichan.vue b/packages/client/src/widgets/aichan.vue
new file mode 100644
index 000000000..828490fd9
--- /dev/null
+++ b/packages/client/src/widgets/aichan.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/client/src/widgets/index.ts b/packages/client/src/widgets/index.ts
index 82d0f5ec8..66bec7c83 100644
--- a/packages/client/src/widgets/index.ts
+++ b/packages/client/src/widgets/index.ts
@@ -22,6 +22,7 @@ export default function(app: App) {
app.component('MkwInstanceCloud', defineAsyncComponent(() => import('./instance-cloud.vue')));
app.component('MkwButton', defineAsyncComponent(() => import('./button.vue')));
app.component('MkwAiscript', defineAsyncComponent(() => import('./aiscript.vue')));
+ app.component('MkwAichan', defineAsyncComponent(() => import('./aichan.vue')));
}
export const widgets = [
@@ -46,4 +47,5 @@ export const widgets = [
'jobQueue',
'button',
'aiscript',
+ 'aichan',
];