2.2.6.5114514
This commit is contained in:
23 files changed
+4497
-49
No files matched your search
@@ -4,3 +4,4 @@ node_modules
|
|||||||
devAssets
|
devAssets
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
android
|
||||||
@@ -6,6 +6,7 @@ WORKDIR /src
|
|||||||
COPY .npmrc package.json package-lock.json /src/
|
COPY .npmrc package.json package-lock.json /src/
|
||||||
RUN npm ci
|
RUN npm ci
|
||||||
COPY . /src/
|
COPY . /src/
|
||||||
|
ENV NODE_OPTIONS=--max_old_space_size=4096
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
@@ -0,0 +1,10 @@
|
|||||||
|
import { CapacitorConfig } from '@capacitor/cli';
|
||||||
|
|
||||||
|
const config: CapacitorConfig = {
|
||||||
|
appId: 'today.icarus.cinny',
|
||||||
|
appName: 'Cinny',
|
||||||
|
webDir: 'dist',
|
||||||
|
bundledWebRuntime: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
Generated
+4151
-29
File diff suppressed because it is too large.
Load diff
+6
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cinny",
|
"name": "cinny",
|
||||||
"version": "2.2.4",
|
"version": "2.2.6",
|
||||||
"description": "Yet another matrix client",
|
"description": "Yet another matrix client",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
"author": "Ajay Bura",
|
"author": "Ajay Bura",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@capacitor/android": "4.7.1",
|
||||||
|
"@capacitor/core": "4.7.1",
|
||||||
"@fontsource/inter": "4.5.14",
|
"@fontsource/inter": "4.5.14",
|
||||||
"@fontsource/roboto": "4.5.8",
|
"@fontsource/roboto": "4.5.8",
|
||||||
"@khanacademy/simple-markdown": "0.8.6",
|
"@khanacademy/simple-markdown": "0.8.6",
|
||||||
@@ -40,7 +42,7 @@
|
|||||||
"katex": "0.16.4",
|
"katex": "0.16.4",
|
||||||
"linkify-html": "4.0.2",
|
"linkify-html": "4.0.2",
|
||||||
"linkifyjs": "4.0.2",
|
"linkifyjs": "4.0.2",
|
||||||
"matrix-js-sdk": "22.0.0",
|
"matrix-js-sdk": "24.0.0",
|
||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-autosize-textarea": "7.1.0",
|
"react-autosize-textarea": "7.1.0",
|
||||||
@@ -56,6 +58,8 @@
|
|||||||
"twemoji": "14.0.2"
|
"twemoji": "14.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@capacitor/assets": "2.0.4",
|
||||||
|
"@capacitor/cli": "4.7.1",
|
||||||
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
|
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
|
||||||
"@rollup/plugin-inject": "5.0.3",
|
"@rollup/plugin-inject": "5.0.3",
|
||||||
"@rollup/plugin-wasm": "6.1.1",
|
"@rollup/plugin-wasm": "6.1.1",
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 26.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 800 800" style="enable-background:new 0 0 800 800;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{stroke:#000000;stroke-width:9;stroke-miterlimit:10;}
|
||||||
|
</style>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M405,442.5H244.8v160.2h-67.1V442.5H17.5v-67.1h160.2V215.2h67.1v160.2H405V442.5z"/>
|
||||||
|
<path class="st0" d="M757,697.8h-75.1V237.2c-30.4,20.2-77.4,30.4-141,30.4v-59.1c91.9,0,144.6-35.4,158.2-106.3H757V697.8z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 688 B |
@@ -50,6 +50,7 @@ import TickMarkIC from '../../../../public/res/ic/outlined/tick-mark.svg';
|
|||||||
import CmdIC from '../../../../public/res/ic/outlined/cmd.svg';
|
import CmdIC from '../../../../public/res/ic/outlined/cmd.svg';
|
||||||
import BinIC from '../../../../public/res/ic/outlined/bin.svg';
|
import BinIC from '../../../../public/res/ic/outlined/bin.svg';
|
||||||
import TransIC from '../../../../public/res/ic/outlined/translate.svg';
|
import TransIC from '../../../../public/res/ic/outlined/translate.svg';
|
||||||
|
import repeatIC from '../../../../public/res/ic/outlined/repeat.svg';
|
||||||
|
|
||||||
import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
|
import { confirmDialog } from '../confirm-dialog/ConfirmDialog';
|
||||||
import { getBlobSafeMimeType } from '../../../util/mimetypes';
|
import { getBlobSafeMimeType } from '../../../util/mimetypes';
|
||||||
@@ -552,6 +553,14 @@ function handleTextTranslate(mEvent) {
|
|||||||
openTextTranslate(mEvent);
|
openTextTranslate(mEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleRepeat(mEvent){
|
||||||
|
console.log(mEvent);
|
||||||
|
const opt = {};
|
||||||
|
opt.msgType = 'm.text';
|
||||||
|
initMatrix.roomsInput.setMessage(mEvent.sender.roomId, mEvent.clearEvent.content.body);
|
||||||
|
await initMatrix.roomsInput.sendInput(mEvent.sender.roomId, opt);
|
||||||
|
}
|
||||||
|
|
||||||
const MessageOptions = React.memo(({ roomTimeline, mEvent, edit, reply }) => {
|
const MessageOptions = React.memo(({ roomTimeline, mEvent, edit, reply }) => {
|
||||||
const { roomId, room } = roomTimeline;
|
const { roomId, room } = roomTimeline;
|
||||||
const mx = initMatrix.matrixClient;
|
const mx = initMatrix.matrixClient;
|
||||||
@@ -591,6 +600,9 @@ const MessageOptions = React.memo(({ roomTimeline, mEvent, edit, reply }) => {
|
|||||||
<MenuItem iconSrc={TransIC} onClick={() => handleTextTranslate(mEvent)}>
|
<MenuItem iconSrc={TransIC} onClick={() => handleTextTranslate(mEvent)}>
|
||||||
Translate
|
Translate
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem iconSrc={repeatIC} onClick={() => handleRepeat(mEvent)}>
|
||||||
|
Repeat
|
||||||
|
</MenuItem>
|
||||||
{(canIRedact || senderId === mx.getUserId()) && (
|
{(canIRedact || senderId === mx.getUserId()) && (
|
||||||
<>
|
<>
|
||||||
<MenuBorder />
|
<MenuBorder />
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ function RoomViewInput({ roomId, roomTimeline, viewEvent }) {
|
|||||||
}, [roomId]);
|
}, [roomId]);
|
||||||
|
|
||||||
const sendBody = async (body, options) => {
|
const sendBody = async (body, options) => {
|
||||||
|
console.log(options)
|
||||||
const opt = options ?? {};
|
const opt = options ?? {};
|
||||||
if (!opt.msgType) opt.msgType = 'm.text';
|
if (!opt.msgType) opt.msgType = 'm.text';
|
||||||
if (typeof opt.autoMarkdown !== 'boolean') opt.autoMarkdown = true;
|
if (typeof opt.autoMarkdown !== 'boolean') opt.autoMarkdown = true;
|
||||||
@@ -218,7 +219,7 @@ function RoomViewInput({ roomId, roomTimeline, viewEvent }) {
|
|||||||
confirmDialog('Invalid Command', `"${cmdName}" is not a valid command.`, 'Alright');
|
confirmDialog('Invalid Command', `"${cmdName}" is not a valid command.`, 'Alright');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (['me', 'shrug', 'plain'].includes(cmdName)) {
|
if (['me', 'shrug', 'plain', 'rainbow'].includes(cmdName)) {
|
||||||
commands[cmdName].exe(roomId, cmdData, sendBody);
|
commands[cmdName].exe(roomId, cmdData, sendBody);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,57 @@ export function processMxidAndReason(data) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function rainbowText(str) {
|
||||||
|
// 定义渐变颜色数组
|
||||||
|
const startColor = [255, 0, 0]; // 红色
|
||||||
|
const middleColor = [0, 255, 0]; // 绿色
|
||||||
|
const endColor = [0, 0, 255]; // 蓝色
|
||||||
|
const numSteps = str.length - 1;
|
||||||
|
const stepsToGreen = Math.round(numSteps / 2);
|
||||||
|
const stepsToBlue = numSteps - stepsToGreen;
|
||||||
|
const stepToGreen = [
|
||||||
|
(middleColor[0] - startColor[0]) / stepsToGreen,
|
||||||
|
(middleColor[1] - startColor[1]) / stepsToGreen,
|
||||||
|
(middleColor[2] - startColor[2]) / stepsToGreen
|
||||||
|
];
|
||||||
|
const stepToBlue = [
|
||||||
|
(endColor[0] - middleColor[0]) / stepsToBlue,
|
||||||
|
(endColor[1] - middleColor[1]) / stepsToBlue,
|
||||||
|
(endColor[2] - middleColor[2]) / stepsToBlue
|
||||||
|
];
|
||||||
|
|
||||||
|
// 生成 HTML 字符串
|
||||||
|
let html = '';
|
||||||
|
const currentColor = startColor.slice();
|
||||||
|
// eslint-disable-next-line no-plusplus
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
// 转换颜色为 16 进制字符串
|
||||||
|
const hexColor = `#${ currentColor.map(c => {
|
||||||
|
const hex = Math.round(c).toString(16);
|
||||||
|
return hex.length === 1 ? `0${ hex}` : hex;
|
||||||
|
}).join('')}`;
|
||||||
|
|
||||||
|
// 将字符包装在 <font> 标签中,并设置颜色
|
||||||
|
const fontTag = `<font color="${hexColor}">${str[i]}</font>`;
|
||||||
|
html += fontTag;
|
||||||
|
|
||||||
|
// 计算下一个颜色
|
||||||
|
if (i < stepsToGreen) {
|
||||||
|
currentColor[0] += stepToGreen[0];
|
||||||
|
currentColor[1] += stepToGreen[1];
|
||||||
|
currentColor[2] += stepToGreen[2];
|
||||||
|
} else {
|
||||||
|
currentColor[0] += stepToBlue[0];
|
||||||
|
currentColor[1] += stepToBlue[1];
|
||||||
|
currentColor[2] += stepToBlue[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const commands = {
|
const commands = {
|
||||||
me: {
|
me: {
|
||||||
name: 'me',
|
name: 'me',
|
||||||
@@ -198,6 +249,14 @@ const commands = {
|
|||||||
roomActions.convertToRoom(roomId);
|
roomActions.convertToRoom(roomId);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
rainbow: {
|
||||||
|
name: 'rainbow',
|
||||||
|
description: 'Rainbow text',
|
||||||
|
exe: (roomId, data, onSuccess) => onSuccess(
|
||||||
|
data,
|
||||||
|
{ msgtype:'m.text', format: 'org.matrix.custom.html', formatted_body: rainbowText(data) },
|
||||||
|
)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function openHelpDialog() {
|
function openHelpDialog() {
|
||||||
|
|||||||
@@ -42,11 +42,15 @@ import BellIC from '../../../../public/res/ic/outlined/bell.svg';
|
|||||||
import InfoIC from '../../../../public/res/ic/outlined/info.svg';
|
import InfoIC from '../../../../public/res/ic/outlined/info.svg';
|
||||||
import PowerIC from '../../../../public/res/ic/outlined/power.svg';
|
import PowerIC from '../../../../public/res/ic/outlined/power.svg';
|
||||||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
||||||
|
import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg';
|
||||||
|
|
||||||
import CinnySVG from '../../../../public/res/svg/cinny.svg';
|
import CinnySVG from '../../../../public/res/svg/cinny.svg';
|
||||||
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
|
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
|
||||||
|
|
||||||
import '../../i18n.jsx'
|
import '../../i18n.jsx'
|
||||||
|
import PeopleSelector from '../../molecules/people-selector/PeopleSelector';
|
||||||
|
import colorMXID from '../../../util/colorMXID';
|
||||||
|
import { openReusableDialog } from '../../../client/action/navigation';
|
||||||
|
|
||||||
let capabilities = {
|
let capabilities = {
|
||||||
privateReadReceipts: false,
|
privateReadReceipts: false,
|
||||||
@@ -101,6 +105,9 @@ function AppearanceSection() {
|
|||||||
{ text: 'Silver' },
|
{ text: 'Silver' },
|
||||||
{ text: 'Dark' },
|
{ text: 'Dark' },
|
||||||
{ text: 'Butter' },
|
{ text: 'Butter' },
|
||||||
|
{ text: 'NGA'},
|
||||||
|
{ text: 'NGA Green'},
|
||||||
|
{ text: '?'}
|
||||||
]}
|
]}
|
||||||
onSelect={(index) => {
|
onSelect={(index) => {
|
||||||
if (settings.useSystemTheme) toggleSystemTheme();
|
if (settings.useSystemTheme) toggleSystemTheme();
|
||||||
@@ -355,10 +362,10 @@ function AboutSection() {
|
|||||||
<div>
|
<div>
|
||||||
<Text variant="h2" weight="medium">
|
<Text variant="h2" weight="medium">
|
||||||
Cinny Mod
|
Cinny Mod
|
||||||
<span className="text text-b3" style={{ margin: '0 var(--sp-extra-tight)' }}>{`v${cons.version}.52`}</span>
|
<span className="text text-b3" style={{ margin: '0 var(--sp-extra-tight)' }}>{`v${cons.version}.5114514`}</span>
|
||||||
</Text>
|
</Text>
|
||||||
<Text>Yet another matrix client</Text>
|
<Text>Yet another matrix client</Text>
|
||||||
<Text>Modded By WHK with magic & love</Text>
|
<Text>Modded By WHK(a.k.a CroiX) with magic & love</Text>
|
||||||
|
|
||||||
<div className="settings-about__btns">
|
<div className="settings-about__btns">
|
||||||
<Button onClick={() => window.open('https://github.com/ajbura/cinny')}>Source code</Button>
|
<Button onClick={() => window.open('https://github.com/ajbura/cinny')}>Source code</Button>
|
||||||
@@ -468,6 +475,51 @@ function Settings() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSwitchUsers = async () => {
|
||||||
|
const loggedInUsers = JSON.parse(window.localStorage.getItem("loggedInUsers"));
|
||||||
|
|
||||||
|
const renderUserSwitcher = () => (
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
loggedInUsers.map((userId) => {
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
const user = mx.getUser(userId);
|
||||||
|
const avatarUrl = user.avatarUrl ? mx.mxcUrlToHttp(user.avatarUrl, 80, 80, 'crop') : null;
|
||||||
|
return (
|
||||||
|
<PeopleSelector
|
||||||
|
key={userId}
|
||||||
|
onClick={() => {
|
||||||
|
if (userId !== window.localStorage.getItem("currentUser")) {
|
||||||
|
window.localStorage.setItem("currentUser", userId);
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
name={user.displayName}
|
||||||
|
avatarSrc={avatarUrl}
|
||||||
|
color={colorMXID(userId)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<Button
|
||||||
|
variant="caution"
|
||||||
|
iconSrc={AddUserIC}
|
||||||
|
onClick={() => {
|
||||||
|
window.localStorage.removeItem("currentUser");
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add user
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
await openReusableDialog(
|
||||||
|
<Text variant="s1" weight="medium">Switch users</Text>,
|
||||||
|
renderUserSwitcher,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopupWindow
|
<PopupWindow
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
@@ -475,6 +527,9 @@ function Settings() {
|
|||||||
title={<Text variant="s1" weight="medium" primary>{t("Settings")}</Text>}
|
title={<Text variant="s1" weight="medium" primary>{t("Settings")}</Text>}
|
||||||
contentOptions={(
|
contentOptions={(
|
||||||
<>
|
<>
|
||||||
|
<Button variant="caution" iconSrc={AddUserIC} onClick={handleSwitchUsers}>
|
||||||
|
Switch users
|
||||||
|
</Button>
|
||||||
<Button variant="danger" iconSrc={PowerIC} onClick={handleLogout}>
|
<Button variant="danger" iconSrc={PowerIC} onClick={handleLogout}>
|
||||||
Logout
|
Logout
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import EyeIC from '../../../../public/res/ic/outlined/eye.svg';
|
|||||||
import EyeBlindIC from '../../../../public/res/ic/outlined/eye-blind.svg';
|
import EyeBlindIC from '../../../../public/res/ic/outlined/eye-blind.svg';
|
||||||
import CinnySvg from '../../../../public/res/svg/cinny.svg';
|
import CinnySvg from '../../../../public/res/svg/cinny.svg';
|
||||||
import SSOButtons from '../../molecules/sso-buttons/SSOButtons';
|
import SSOButtons from '../../molecules/sso-buttons/SSOButtons';
|
||||||
|
import colorMXID from '../../../util/colorMXID';
|
||||||
|
import PeopleSelector from '../../molecules/people-selector/PeopleSelector';
|
||||||
|
|
||||||
const LOCALPART_SIGNUP_REGEX = /^[a-z0-9_\-.=/]+$/;
|
const LOCALPART_SIGNUP_REGEX = /^[a-z0-9_\-.=/]+$/;
|
||||||
const BAD_LOCALPART_ERROR = 'Username can only contain characters a-z, 0-9, or \'=_-./\'';
|
const BAD_LOCALPART_ERROR = 'Username can only contain characters a-z, 0-9, or \'=_-./\'';
|
||||||
@@ -537,13 +539,14 @@ function AuthCard() {
|
|||||||
function Auth() {
|
function Auth() {
|
||||||
const [loginToken, setLoginToken] = useState(getUrlPrams('loginToken'));
|
const [loginToken, setLoginToken] = useState(getUrlPrams('loginToken'));
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
useEffect(async () => {
|
useEffect(async () => {
|
||||||
if (!loginToken) return;
|
if (!loginToken) return;
|
||||||
if (localStorage.getItem(cons.secretKey.BASE_URL) === undefined) {
|
if (window.userLocalStorage.getItem(cons.secretKey.BASE_URL) === undefined) {
|
||||||
setLoginToken(null);
|
setLoginToken(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const baseUrl = localStorage.getItem(cons.secretKey.BASE_URL);
|
const baseUrl = window.userLocalStorage.getItem(cons.secretKey.BASE_URL);
|
||||||
try {
|
try {
|
||||||
await auth.loginWithToken(baseUrl, loginToken);
|
await auth.loginWithToken(baseUrl, loginToken);
|
||||||
|
|
||||||
@@ -567,6 +570,37 @@ function Auth() {
|
|||||||
<Text variant="h2" weight="medium">Cinny</Text>
|
<Text variant="h2" weight="medium">Cinny</Text>
|
||||||
</TitleWrapper>
|
</TitleWrapper>
|
||||||
</Header>
|
</Header>
|
||||||
|
{(() => {
|
||||||
|
let loggedInUsers = JSON.parse(window.localStorage.getItem("loggedInUsers"));
|
||||||
|
if (!loggedInUsers) {
|
||||||
|
// 检查currentUser是否存在
|
||||||
|
const currentUser = window.localStorage.getItem('cinny_user_id');
|
||||||
|
if(currentUser){
|
||||||
|
// 开始迁移
|
||||||
|
window.localStorage.setItem('loggedInUsers', JSON.stringify([currentUser]));
|
||||||
|
window.localStorage.setItem('currentUser', currentUser);
|
||||||
|
window.localStorage.setItem(`${currentUser}.cinny_access_token`, window.localStorage.getItem('cinny_access_token'));
|
||||||
|
window.localStorage.setItem(`${currentUser}.cinny_device_id`, window.localStorage.getItem('cinny_device_id'));
|
||||||
|
window.localStorage.setItem(`${currentUser}.cinny_hs_base_url`, window.localStorage.getItem('cinny_hs_base_url'));
|
||||||
|
window.localStorage.setItem(`${currentUser}.cinny_user_id`, window.localStorage.getItem('cinny_user_id'));
|
||||||
|
} else{
|
||||||
|
loggedInUsers = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
loggedInUsers.map((userId) => (
|
||||||
|
<PeopleSelector
|
||||||
|
key={userId}
|
||||||
|
onClick={() => {
|
||||||
|
window.localStorage.setItem("currentUser", userId);
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
|
name={userId}
|
||||||
|
color={colorMXID(userId)}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
);
|
||||||
|
})()}
|
||||||
<div className="auth-card__content">
|
<div className="auth-card__content">
|
||||||
<AuthCard />
|
<AuthCard />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ function Client() {
|
|||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<div className="loading-display">
|
<div className="loading-display">
|
||||||
|
{/* <div className="watermark">Cinny Mod</div> */}
|
||||||
<div className="loading__menu">
|
<div className="loading__menu">
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
@@ -170,6 +172,18 @@ function Client() {
|
|||||||
initMatrix.roomsInput.emit(cons.events.roomsInput.ATTACHMENT_SET, file);
|
initMatrix.roomsInput.emit(cons.events.roomsInput.ATTACHMENT_SET, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 盲水印实验性特性
|
||||||
|
// const watermark = document.querySelector('.watermark');
|
||||||
|
// for (let i = 0; i < window.innerHeight / watermark.offsetHeight + 1; i += 0.25) {
|
||||||
|
// for (let j = 0; j < window.innerWidth / watermark.offsetWidth + 1; j += 0.25) {
|
||||||
|
// const clone = watermark.cloneNode(true);
|
||||||
|
// clone.style.top = i * watermark.offsetHeight + 'px';
|
||||||
|
// clone.style.left = j * watermark.offsetWidth + 'px';
|
||||||
|
// document.body.appendChild(clone);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="client-container"
|
className="client-container"
|
||||||
@@ -178,6 +192,7 @@ function Client() {
|
|||||||
onDragLeave={handleDragLeave}
|
onDragLeave={handleDragLeave}
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
>
|
>
|
||||||
|
{/* <div className="watermark">Cinny Mod</div> */}
|
||||||
<div className={`navigation__wrapper ${settings.hideNavigation && roomSelected ? toggleHidden : ''}`} ref={navWrapperRef}>
|
<div className={`navigation__wrapper ${settings.hideNavigation && roomSelected ? toggleHidden : ''}`} ref={navWrapperRef}>
|
||||||
<Navigation />
|
<Navigation />
|
||||||
</div>
|
</div>
|
||||||
@@ -191,6 +206,7 @@ function Client() {
|
|||||||
<DragDrop isOpen={dragCounter !== 0} />
|
<DragDrop isOpen={dragCounter !== 0} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Client;
|
export default Client;
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
import * as sdk from 'matrix-js-sdk';
|
import * as sdk from 'matrix-js-sdk';
|
||||||
import cons from '../state/cons';
|
import cons from '../state/cons';
|
||||||
|
import NamespacedStorage from '../state/NamespacedStorage';
|
||||||
|
|
||||||
function updateLocalStore(accessToken, deviceId, userId, baseUrl) {
|
function updateLocalStore(accessToken, deviceId, userId, baseUrl) {
|
||||||
localStorage.setItem(cons.secretKey.ACCESS_TOKEN, accessToken);
|
window.localStorage.setItem("currentUser", userId);
|
||||||
localStorage.setItem(cons.secretKey.DEVICE_ID, deviceId);
|
const loggedInUsers = new Set(JSON.parse(window.localStorage.getItem("loggedInUsers")));
|
||||||
localStorage.setItem(cons.secretKey.USER_ID, userId);
|
loggedInUsers.add(userId);
|
||||||
localStorage.setItem(cons.secretKey.BASE_URL, baseUrl);
|
window.localStorage.setItem("loggedInUsers", JSON.stringify(Array.from(loggedInUsers)));
|
||||||
|
|
||||||
|
window.userLocalStorage = new NamespacedStorage(userId, window.localStorage);
|
||||||
|
|
||||||
|
window.userLocalStorage.setItem(cons.secretKey.ACCESS_TOKEN, accessToken);
|
||||||
|
window.userLocalStorage.setItem(cons.secretKey.DEVICE_ID, deviceId);
|
||||||
|
window.userLocalStorage.setItem(cons.secretKey.USER_ID, userId);
|
||||||
|
window.userLocalStorage.setItem(cons.secretKey.BASE_URL, baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTemporaryClient(baseUrl) {
|
function createTemporaryClient(baseUrl) {
|
||||||
@@ -14,7 +22,7 @@ function createTemporaryClient(baseUrl) {
|
|||||||
|
|
||||||
async function startSsoLogin(baseUrl, type, idpId) {
|
async function startSsoLogin(baseUrl, type, idpId) {
|
||||||
const client = createTemporaryClient(baseUrl);
|
const client = createTemporaryClient(baseUrl);
|
||||||
localStorage.setItem(cons.secretKey.BASE_URL, client.baseUrl);
|
window.userLocalStorage.setItem(cons.secretKey.BASE_URL, client.baseUrl);
|
||||||
window.location.href = client.getSsoLoginUrl(window.location.href, type, idpId);
|
window.location.href = client.getSsoLoginUrl(window.location.href, type, idpId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,12 @@ class InitMatrix extends EventEmitter {
|
|||||||
// ignore if failed to logout
|
// ignore if failed to logout
|
||||||
}
|
}
|
||||||
await this.matrixClient.clearStores();
|
await this.matrixClient.clearStores();
|
||||||
window.localStorage.clear();
|
window.userLocalStorage.clear();
|
||||||
|
const currentUser = window.localStorage.getItem("currentUser");
|
||||||
|
const loggedInUsers = new Set(JSON.parse(window.localStorage.getItem("loggedInUsers")));
|
||||||
|
loggedInUsers.delete(currentUser);
|
||||||
|
window.localStorage.setItem("loggedInUsers", JSON.stringify(loggedInUsers));
|
||||||
|
window.localStorage.removeItem("currentUser");
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
class NamespacedStorage {
|
||||||
|
#namespace;
|
||||||
|
|
||||||
|
#storage;
|
||||||
|
|
||||||
|
#cache;
|
||||||
|
|
||||||
|
constructor(namespace, storage) {
|
||||||
|
this.#namespace = namespace;
|
||||||
|
this.#storage = storage;
|
||||||
|
|
||||||
|
this.#cache = new Set();
|
||||||
|
for (let i = 0; i < this.#storage.length; i++) {
|
||||||
|
let key = this.#storage.key(i);
|
||||||
|
if (key.startsWith(`${this.#namespace}.`)) {
|
||||||
|
this.#cache.add(key.replace(`${this.#namespace}.`, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key(n) {
|
||||||
|
return this.#cache[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
getItem(key) {
|
||||||
|
return this.#storage.getItem(`${this.#namespace}.${key}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
setItem(key, value) {
|
||||||
|
this.#storage.setItem(`${this.#namespace}.${key}`, value);
|
||||||
|
this.#cache.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(key) {
|
||||||
|
this.#storage.removeItem(`${this.#namespace}.${key}`);
|
||||||
|
this.#cache.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
for (let key of this.#cache) {
|
||||||
|
this.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NamespacedStorage;
|
||||||
@@ -298,7 +298,9 @@ class Notifications extends EventEmitter {
|
|||||||
_deletePopupRoomNotis(roomId) {
|
_deletePopupRoomNotis(roomId) {
|
||||||
this.roomIdToPopupNotis.get(roomId)?.forEach((n) => {
|
this.roomIdToPopupNotis.get(roomId)?.forEach((n) => {
|
||||||
this.eventIdToPopupNoti.delete(n.tag);
|
this.eventIdToPopupNoti.delete(n.tag);
|
||||||
n.close();
|
if(n.close){
|
||||||
|
n.close();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.roomIdToPopupNotis.delete(roomId);
|
this.roomIdToPopupNotis.delete(roomId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,6 +211,11 @@ class RoomsInput extends EventEmitter {
|
|||||||
content.formatted_body = body.html;
|
content.formatted_body = body.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(options.format === 'org.matrix.custom.html'){
|
||||||
|
content.format = 'org.matrix.custom.html';
|
||||||
|
content.formatted_body = options.formatted_body;
|
||||||
|
}
|
||||||
|
|
||||||
if (edit) {
|
if (edit) {
|
||||||
content['m.new_content'] = { ...content };
|
content['m.new_content'] = { ...content };
|
||||||
content['m.relates_to'] = {
|
content['m.relates_to'] = {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
import NamespacedStorage from './NamespacedStorage';
|
||||||
import cons from './cons';
|
import cons from './cons';
|
||||||
|
|
||||||
function getSecret(key) {
|
function getSecret(key) {
|
||||||
return localStorage.getItem(key);
|
const user = global.localStorage.getItem("currentUser");
|
||||||
|
const storage = new NamespacedStorage(user, global.localStorage);
|
||||||
|
return storage.getItem(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAuthenticated = () => getSecret(cons.secretKey.ACCESS_TOKEN) !== null;
|
const isAuthenticated = () => getSecret(cons.secretKey.ACCESS_TOKEN) !== null;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const cons = {
|
const cons = {
|
||||||
version: '2.2.4',
|
version: '2.2.6',
|
||||||
secretKey: {
|
secretKey: {
|
||||||
ACCESS_TOKEN: 'cinny_access_token',
|
ACCESS_TOKEN: 'cinny_access_token',
|
||||||
DEVICE_ID: 'cinny_device_id',
|
DEVICE_ID: 'cinny_device_id',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import appDispatcher from '../dispatcher';
|
|||||||
import cons from './cons';
|
import cons from './cons';
|
||||||
|
|
||||||
function getSettings() {
|
function getSettings() {
|
||||||
const settings = localStorage.getItem('settings');
|
const settings = window.localStorage.getItem('settings');
|
||||||
if (settings === null) return null;
|
if (settings === null) return null;
|
||||||
return JSON.parse(settings);
|
return JSON.parse(settings);
|
||||||
}
|
}
|
||||||
@@ -13,14 +13,14 @@ function setSettings(key, value) {
|
|||||||
let settings = getSettings();
|
let settings = getSettings();
|
||||||
if (settings === null) settings = {};
|
if (settings === null) settings = {};
|
||||||
settings[key] = value;
|
settings[key] = value;
|
||||||
localStorage.setItem('settings', JSON.stringify(settings));
|
window.localStorage.setItem('settings', JSON.stringify(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
class Settings extends EventEmitter {
|
class Settings extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme'];
|
this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme', 'nga-theme', 'nga-green-theme', 'troll'];
|
||||||
this.themeIndex = this.getThemeIndex();
|
this.themeIndex = this.getThemeIndex();
|
||||||
this.translationIndex = this.getTranslationAPIIndex();
|
this.translationIndex = this.getTranslationAPIIndex();
|
||||||
this.translationLanguage = this.getTranslationLanguage();
|
this.translationLanguage = this.getTranslationLanguage();
|
||||||
|
|||||||
@@ -306,6 +306,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// .watermark {
|
||||||
|
// position: fixed;
|
||||||
|
// top: 0;
|
||||||
|
// left: 0;
|
||||||
|
// width: 100%;
|
||||||
|
// height: 100%;
|
||||||
|
// z-index: 9999;
|
||||||
|
// font-size: 24px;
|
||||||
|
// color: #ccc;
|
||||||
|
// text-align: center;
|
||||||
|
// opacity: 0.03;
|
||||||
|
// transform: rotate(-45deg);
|
||||||
|
// transform-origin: 0 0;
|
||||||
|
// user-select: none;
|
||||||
|
// pointer-events: none;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
.butter-theme {
|
.butter-theme {
|
||||||
/* background color | --bg-[background type]: value */
|
/* background color | --bg-[background type]: value */
|
||||||
--bg-surface: hsl(64, 6%, 14%);
|
--bg-surface: hsl(64, 6%, 14%);
|
||||||
@@ -331,6 +349,40 @@
|
|||||||
--ic-surface-low: rgba(255, 251, 222, 64%);
|
--ic-surface-low: rgba(255, 251, 222, 64%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nga-theme {
|
||||||
|
/* background color | --bg-[background type]: value */
|
||||||
|
--bg-surface: rgb(254,248,231);
|
||||||
|
--bg-surface-transparent: hsla(0, 0%, 95%, 0);
|
||||||
|
--bg-surface-low: rgb(244,232,202);
|
||||||
|
--bg-surface-low-transparent: hsla(0, 0%, 91%, 0);
|
||||||
|
--bg-surface-extra-low: rgb(244,232,202);
|
||||||
|
--bg-surface-extra-low-transparent: hsla(0, 0%, 91%, 0);
|
||||||
|
--bg-positive: rgb(214, 189, 127);
|
||||||
|
--bg-primary: rgb(86, 23, 1);
|
||||||
|
--bg-primary-hover: rgb(180, 116, 98);
|
||||||
|
--bg-primary-active: rgb(180, 116, 98);
|
||||||
|
--ic-surface-normal: rgb(86, 23, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nga-green-theme {
|
||||||
|
/* background color | --bg-[background type]: value */
|
||||||
|
--bg-surface: rgb(241,247,245);
|
||||||
|
--bg-surface-transparent: hsla(0, 0%, 95%, 0);
|
||||||
|
--bg-surface-low: rgb(226,239,235);
|
||||||
|
--bg-surface-low-transparent: hsla(0, 0%, 91%, 0);
|
||||||
|
--bg-surface-extra-low: rgb(226,239,235);
|
||||||
|
--bg-surface-extra-low-transparent: hsla(0, 0%, 91%, 0);
|
||||||
|
--bg-positive: rgb(212,222,219);
|
||||||
|
--bg-primary: rgb(42,67,73);
|
||||||
|
--bg-primary-hover: rgb(125,162,160);
|
||||||
|
--bg-primary-active: rgb(125,162,160);
|
||||||
|
--ic-surface-normal: rgb(42,67,73);
|
||||||
|
}
|
||||||
|
|
||||||
|
.troll {
|
||||||
|
filter: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='3d-glasses' x='0' y='0' width='1' height='1'%3E%3CfeGaussianBlur in='SourceGraphic' stdDeviation='2' /%3E%3CfeColorMatrix values='1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 100 0' /%3E%3CfeOffset dx='5' dy='5' /%3E%3CfeColorMatrix values='0.5 0 0 0 0 0 0.5 0 0 0 0 0 0.5 0 0 0 0 0 1 0' /%3E%3CfeBlend mode='multiply' in2='SourceGraphic' /%3E%3C/filter%3E%3C/svg%3E#3d-glasses");
|
||||||
|
}
|
||||||
|
|
||||||
.font-primary {
|
.font-primary {
|
||||||
font-family: var(--font-primary);
|
font-family: var(--font-primary);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import parse from 'html-react-parser';
|
|||||||
import twemoji from 'twemoji';
|
import twemoji from 'twemoji';
|
||||||
import { sanitizeText } from './sanitize';
|
import { sanitizeText } from './sanitize';
|
||||||
|
|
||||||
export const TWEMOJI_BASE_URL = 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/';
|
export const TWEMOJI_BASE_URL = 'https://fastly.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/';
|
||||||
|
|
||||||
const Math = lazy(() => import('../app/atoms/math/Math'));
|
const Math = lazy(() => import('../app/atoms/math/Math'));
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user