Compare commits

...

14 commits

Author SHA1 Message Date
array-in-a-matrix 23580c9de7 remove twemoji 2023-04-08 01:36:28 -04:00
array-in-a-matrix 7a0fe843dc remove lazy loading 2023-04-08 00:45:58 -04:00
array-in-a-matrix 2ffc26b0dc enable LaTeX by default 2023-04-08 00:27:38 -04:00
array-in-a-matrix 4ac8d84a08 remove twemoji 2023-04-05 11:37:28 -04:00
array-in-a-matrix 0cc57aae49 default homeserver 2023-04-03 13:38:13 -04:00
Array in a Matrix cc116ad8dc
Merge pull request #3 from cinnyapp/dev
fix: Fixed small typo an cross signing reset modal (#1112)
2023-03-31 09:15:12 -07:00
Array in a Matrix 08493e7d54
Merge pull request #2 from cinnyapp/dev
Fix docker build failing
2023-03-29 07:38:11 -07:00
Array in a Matrix 5244c9d6b8
Merge pull request #1 from cinnyapp/dev
fix vulnerabilities
2023-03-28 21:00:50 -07:00
array-in-a-matrix 947bbf3be6 fix unthemed 'jump to unread messages' 2023-03-28 14:16:27 -04:00
array-in-a-matrix 042e4f5a03 Almond Dark theme 2023-03-21 09:26:43 -04:00
array-in-a-matrix 227c552f1e fix unthemed badge 2023-03-20 16:01:46 -04:00
array-in-a-matrix aa53e37f6f added cyberpunk theme 2023-03-20 15:18:35 -04:00
array-in-a-matrix a4e0f7a2c8 add Nord Dark theme 2023-03-20 13:40:32 -04:00
array-in-a-matrix 111af25c3a update dependencies 2023-03-17 09:16:35 -04:00
14 changed files with 358 additions and 166 deletions

View file

@ -1,6 +1,7 @@
{
"defaultHomeserver": 3,
"defaultHomeserver": 0,
"homeserverList": [
"chatinamatrix.xyz",
"converser.eu",
"envs.net",
"halogen.city",

18
package-lock.json generated
View file

@ -3676,9 +3676,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@ -4970,9 +4970,9 @@
}
},
"node_modules/tsconfig-paths/node_modules/json5": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
"dependencies": {
"minimist": "^1.2.0"
@ -5055,9 +5055,9 @@
}
},
"node_modules/ua-parser-js": {
"version": "0.7.32",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz",
"integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==",
"version": "0.7.34",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.34.tgz",
"integrity": "sha512-cJMeh/eOILyGu0ejgTKB95yKT3zOenSe9UGE3vj6WfiOwgGYnmATUsnDixMFvdU+rNMvWih83hrUP8VwhF9yXQ==",
"funding": [
{
"type": "opencollective",

View file

@ -210,19 +210,13 @@ const MessageBody = React.memo(({
let content = null;
if (isCustomHTML) {
try {
content = twemojify(
sanitizeCustomHtml(initMatrix.matrixClient, body),
undefined,
true,
false,
true,
);
content = twemojify(sanitizeCustomHtml(initMatrix.matrixClient, body), undefined, true, false);
} catch {
console.error('Malformed custom html: ', body);
content = twemojify(body, undefined);
content = twemojify(body);
}
} else {
content = twemojify(body, undefined, true);
content = twemojify(body);
}
// Determine if this message should render with large emojis

View file

@ -161,7 +161,7 @@ function RoomProfile({ roomId }) {
)}
</div>
<Text variant="b3">{room.getCanonicalAlias() || room.roomId}</Text>
{roomTopic && <Text variant="b2">{twemojify(roomTopic, undefined, true)}</Text>}
{roomTopic && <Text variant="b2">{twemojify(roomTopic)}</Text>}
</div>
);

View file

@ -33,7 +33,7 @@ function RoomTile({
</Text>
{
desc !== null && (typeof desc === 'string')
? <Text className="room-tile__content__desc" variant="b2">{twemojify(desc, undefined, true)}</Text>
? <Text className="room-tile__content__desc" variant="b2">{twemojify(desc)}</Text>
: desc
}
</div>

View file

@ -55,7 +55,6 @@ const EmojiGroup = React.memo(({ name, groupEmojis }) => {
unicode: emoji.unicode,
shortcodes: emoji.shortcodes?.toString(),
hexcode: emoji.hexcode,
loading: 'lazy',
}),
base: TWEMOJI_BASE_URL,
})
@ -65,7 +64,6 @@ const EmojiGroup = React.memo(({ name, groupEmojis }) => {
<img
className="emoji"
draggable="false"
loading="lazy"
alt={emoji.shortcode}
unicode={`:${emoji.shortcode}:`}
shortcodes={emoji.shortcode}
@ -340,7 +338,7 @@ function EmojiBoard({ onSelect, searchRef }) {
</ScrollView>
</div>
<div ref={emojiInfo} className="emoji-board__content__info">
<div>{parse(twemoji.parse('🙂', { base: TWEMOJI_BASE_URL }))}</div>
<div>{parse('🙂')}</div>
<Text>:slight_smile:</Text>
</div>
</div>

View file

@ -5,7 +5,7 @@ import './RoomViewCmdBar.scss';
import parse from 'html-react-parser';
import twemoji from 'twemoji';
import { twemojify, TWEMOJI_BASE_URL } from '../../../util/twemojify';
import { twemojify } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix';
import { getEmojiForCompletion } from '../emoji-board/custom-emoji';
@ -53,15 +53,7 @@ function renderSuggestions({ prefix, option, suggestions }, fireCmd) {
// Renders a small Twemoji
function renderTwemoji(emoji) {
return parse(
twemoji.parse(emoji.unicode, {
attributes: () => ({
unicode: emoji.unicode,
shortcodes: emoji.shortcodes?.toString(),
}),
base: TWEMOJI_BASE_URL,
})
);
return parse(emoji.unicode);
}
// Render a custom emoji

View file

@ -62,7 +62,7 @@ function RoomIntroContainer({ event, timeline }) {
avatarSrc = isDM ? room.getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 80, 80, 'crop') : avatarSrc;
const heading = isDM ? room.name : `Welcome to ${room.name}`;
const topic = twemojify(roomTopic || '', undefined, true);
const topic = twemojify(roomTopic || '');
const nameJsx = twemojify(room.name);
const desc = isDM
? (

View file

@ -6,8 +6,12 @@ import cons from '../../../client/state/cons';
import settings from '../../../client/state/settings';
import navigation from '../../../client/state/navigation';
import {
toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents,
toggleNotifications, toggleNotificationSounds,
toggleSystemTheme,
toggleMarkdown,
toggleMembershipEvents,
toggleNickAvatarEvents,
toggleNotifications,
toggleNotificationSounds,
} from '../../../client/action/settings';
import { usePermission } from '../../hooks/usePermission';
@ -53,17 +57,20 @@ function AppearanceSection() {
<MenuHeader>Theme</MenuHeader>
<SettingTile
title="Follow system theme"
options={(
options={
<Toggle
isActive={settings.useSystemTheme}
onToggle={() => { toggleSystemTheme(); updateState({}); }}
onToggle={() => {
toggleSystemTheme();
updateState({});
}}
/>
)}
}
content={<Text variant="b3">Use light or dark mode based on the system settings.</Text>}
/>
<SettingTile
title="Theme"
content={(
content={
<SegmentedControls
selected={settings.useSystemTheme ? -1 : settings.getThemeIndex()}
segments={[
@ -71,6 +78,9 @@ function AppearanceSection() {
{ text: 'Silver' },
{ text: 'Dark' },
{ text: 'Butter' },
{ text: 'Nord Dark' },
{ text: 'Cyberpunk' },
{ text: 'Almond Dark'},
]}
onSelect={(index) => {
if (settings.useSystemTheme) toggleSystemTheme();
@ -78,40 +88,56 @@ function AppearanceSection() {
updateState({});
}}
/>
)}
}
/>
</div>
<div className="settings-appearance__card">
<MenuHeader>Room messages</MenuHeader>
<SettingTile
title="Markdown formatting"
options={(
options={
<Toggle
isActive={settings.isMarkdown}
onToggle={() => { toggleMarkdown(); updateState({}); }}
onToggle={() => {
toggleMarkdown();
updateState({});
}}
/>
)}
}
content={<Text variant="b3">Format messages with markdown syntax before sending.</Text>}
/>
<SettingTile
title="Hide membership events"
options={(
options={
<Toggle
isActive={settings.hideMembershipEvents}
onToggle={() => { toggleMembershipEvents(); updateState({}); }}
onToggle={() => {
toggleMembershipEvents();
updateState({});
}}
/>
)}
content={<Text variant="b3">Hide membership change messages from room timeline. (Join, Leave, Invite, Kick and Ban)</Text>}
}
content={
<Text variant="b3">
Hide membership change messages from room timeline. (Join, Leave, Invite, Kick and
Ban)
</Text>
}
/>
<SettingTile
title="Hide nick/avatar events"
options={(
options={
<Toggle
isActive={settings.hideNickAvatarEvents}
onToggle={() => { toggleNickAvatarEvents(); updateState({}); }}
onToggle={() => {
toggleNickAvatarEvents();
updateState({});
}}
/>
)}
content={<Text variant="b3">Hide nick and avatar change messages from room timeline.</Text>}
}
content={
<Text variant="b3">Hide nick and avatar change messages from room timeline.</Text>
}
/>
</div>
</div>
@ -119,13 +145,20 @@ function AppearanceSection() {
}
function NotificationsSection() {
const [permission, setPermission] = usePermission('notifications', window.Notification?.permission);
const [permission, setPermission] = usePermission(
'notifications',
window.Notification?.permission
);
const [, updateState] = useState({});
const renderOptions = () => {
if (window.Notification === undefined) {
return <Text className="settings-notifications__not-supported">Not supported in this browser.</Text>;
return (
<Text className="settings-notifications__not-supported">
Not supported in this browser.
</Text>
);
}
if (permission === 'granted') {
@ -162,12 +195,15 @@ function NotificationsSection() {
/>
<SettingTile
title="Notification Sound"
options={(
options={
<Toggle
isActive={settings.isNotificationSounds}
onToggle={() => { toggleNotificationSounds(); updateState({}); }}
onToggle={() => {
toggleNotificationSounds();
updateState({});
}}
/>
)}
}
content={<Text variant="b3">Play sound when new messages arrive.</Text>}
/>
</div>
@ -181,8 +217,12 @@ function NotificationsSection() {
function EmojiSection() {
return (
<>
<div className="settings-emoji__card"><ImagePackUser /></div>
<div className="settings-emoji__card"><ImagePackGlobal /></div>
<div className="settings-emoji__card">
<ImagePackUser />
</div>
<div className="settings-emoji__card">
<ImagePackGlobal />
</div>
</>
);
}
@ -200,21 +240,29 @@ function SecuritySection() {
<MenuHeader>Export/Import encryption keys</MenuHeader>
<SettingTile
title="Export E2E room keys"
content={(
content={
<>
<Text variant="b3">Export end-to-end encryption room keys to decrypt old messages in other session. In order to encrypt keys you need to set a password, which will be used while importing.</Text>
<Text variant="b3">
Export end-to-end encryption room keys to decrypt old messages in other session. In
order to encrypt keys you need to set a password, which will be used while
importing.
</Text>
<ExportE2ERoomKeys />
</>
)}
}
/>
<SettingTile
title="Import E2E room keys"
content={(
content={
<>
<Text variant="b3">{'To decrypt older messages, Export E2EE room keys from Element (Settings > Security & Privacy > Encryption > Cryptography) and import them here. Imported keys are encrypted so you\'ll have to enter the password you set in order to decrypt it.'}</Text>
<Text variant="b3">
{
"To decrypt older messages, Export E2EE room keys from Element (Settings > Security & Privacy > Encryption > Cryptography) and import them here. Imported keys are encrypted so you'll have to enter the password you set in order to decrypt it."
}
</Text>
<ImportE2ERoomKeys />
</>
)}
}
/>
</div>
</div>
@ -231,14 +279,21 @@ function AboutSection() {
<div>
<Text variant="h2" weight="medium">
Cinny
<span className="text text-b3" style={{ margin: '0 var(--sp-extra-tight)' }}>{`v${cons.version}`}</span>
<span
className="text text-b3"
style={{ margin: '0 var(--sp-extra-tight)' }}
>{`v${cons.version}`}</span>
</Text>
<Text>Yet another matrix client</Text>
<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>
<Button onClick={() => window.open('https://cinny.in/#sponsor')}>Support</Button>
<Button onClick={() => initMatrix.clearCacheAndReload()} variant="danger">Clear cache & reload</Button>
<Button onClick={() => initMatrix.clearCacheAndReload()} variant="danger">
Clear cache & reload
</Button>
</div>
</div>
</div>
@ -248,16 +303,78 @@ function AboutSection() {
<div className="settings-about__credits">
<ul>
<li>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
<Text>The <a href="https://github.com/matrix-org/matrix-js-sdk" rel="noreferrer noopener" target="_blank">matrix-js-sdk</a> is © <a href="https://matrix.org/foundation" rel="noreferrer noopener" target="_blank">The Matrix.org Foundation C.I.C</a> used under the terms of <a href="http://www.apache.org/licenses/LICENSE-2.0" rel="noreferrer noopener" target="_blank">Apache 2.0</a>.</Text>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */}
<Text>
The{' '}
<a
href="https://github.com/matrix-org/matrix-js-sdk"
rel="noreferrer noopener"
target="_blank"
>
matrix-js-sdk
</a>{' '}
is ©{' '}
<a href="https://matrix.org/foundation" rel="noreferrer noopener" target="_blank">
The Matrix.org Foundation C.I.C
</a>{' '}
used under the terms of{' '}
<a
href="http://www.apache.org/licenses/LICENSE-2.0"
rel="noreferrer noopener"
target="_blank"
>
Apache 2.0
</a>
.
</Text>
</li>
<li>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
<Text>The <a href="https://twemoji.twitter.com" target="_blank" rel="noreferrer noopener">Twemoji</a> emoji art is © <a href="https://twemoji.twitter.com" target="_blank" rel="noreferrer noopener">Twitter, Inc and other contributors</a> used under the terms of <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer noopener">CC-BY 4.0</a>.</Text>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */}
<Text>
The{' '}
<a href="https://twemoji.twitter.com" target="_blank" rel="noreferrer noopener">
Twemoji
</a>{' '}
emoji art is ©{' '}
<a href="https://twemoji.twitter.com" target="_blank" rel="noreferrer noopener">
Twitter, Inc and other contributors
</a>{' '}
used under the terms of{' '}
<a
href="https://creativecommons.org/licenses/by/4.0/"
target="_blank"
rel="noreferrer noopener"
>
CC-BY 4.0
</a>
.
</Text>
</li>
<li>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */ }
<Text>The <a href="https://material.io/design/sound/sound-resources.html" target="_blank" rel="noreferrer noopener">Material sound resources</a> are © <a href="https://google.com" target="_blank" rel="noreferrer noopener">Google</a> used under the terms of <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer noopener">CC-BY 4.0</a>.</Text>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */}
<Text>
The{' '}
<a
href="https://material.io/design/sound/sound-resources.html"
target="_blank"
rel="noreferrer noopener"
>
Material sound resources
</a>{' '}
are ©{' '}
<a href="https://google.com" target="_blank" rel="noreferrer noopener">
Google
</a>{' '}
used under the terms of{' '}
<a
href="https://creativecommons.org/licenses/by/4.0/"
target="_blank"
rel="noreferrer noopener"
>
CC-BY 4.0
</a>
.
</Text>
</li>
</ul>
</div>
@ -273,32 +390,38 @@ export const tabText = {
SECURITY: 'Security',
ABOUT: 'About',
};
const tabItems = [{
text: tabText.APPEARANCE,
iconSrc: SunIC,
disabled: false,
render: () => <AppearanceSection />,
}, {
text: tabText.NOTIFICATIONS,
iconSrc: BellIC,
disabled: false,
render: () => <NotificationsSection />,
}, {
text: tabText.EMOJI,
iconSrc: EmojiIC,
disabled: false,
render: () => <EmojiSection />,
}, {
text: tabText.SECURITY,
iconSrc: LockIC,
disabled: false,
render: () => <SecuritySection />,
}, {
text: tabText.ABOUT,
iconSrc: InfoIC,
disabled: false,
render: () => <AboutSection />,
}];
const tabItems = [
{
text: tabText.APPEARANCE,
iconSrc: SunIC,
disabled: false,
render: () => <AppearanceSection />,
},
{
text: tabText.NOTIFICATIONS,
iconSrc: BellIC,
disabled: false,
render: () => <NotificationsSection />,
},
{
text: tabText.EMOJI,
iconSrc: EmojiIC,
disabled: false,
render: () => <EmojiSection />,
},
{
text: tabText.SECURITY,
iconSrc: LockIC,
disabled: false,
render: () => <SecuritySection />,
},
{
text: tabText.ABOUT,
iconSrc: InfoIC,
disabled: false,
render: () => <AboutSection />,
},
];
function useWindowToggle(setSelectedTab) {
const [isOpen, setIsOpen] = useState(false);
@ -326,7 +449,14 @@ function Settings() {
const handleTabChange = (tabItem) => setSelectedTab(tabItem);
const handleLogout = async () => {
if (await confirmDialog('Logout', 'Are you sure that you want to logout your session?', 'Logout', 'danger')) {
if (
await confirmDialog(
'Logout',
'Are you sure that you want to logout your session?',
'Logout',
'danger'
)
) {
initMatrix.logout();
}
};
@ -335,15 +465,19 @@ function Settings() {
<PopupWindow
isOpen={isOpen}
className="settings-window"
title={<Text variant="s1" weight="medium" primary>Settings</Text>}
contentOptions={(
title={
<Text variant="s1" weight="medium" primary>
Settings
</Text>
}
contentOptions={
<>
<Button variant="danger" iconSrc={PowerIC} onClick={handleLogout}>
Logout
</Button>
<IconButton src={CrossIC} onClick={requestClose} tooltip="Close" />
</>
)}
}
onRequestClose={requestClose}
>
{isOpen && (
@ -354,9 +488,7 @@ function Settings() {
defaultSelected={tabItems.findIndex((tab) => tab.text === selectedTab.text)}
onSelect={handleTabChange}
/>
<div className="settings-window__cards-wrapper">
{ selectedTab.render() }
</div>
<div className="settings-window__cards-wrapper">{selectedTab.render()}</div>
</div>
)}
</PopupWindow>

View file

@ -151,7 +151,7 @@ function SpaceManageItem({
: <Button variant="primary" onClick={handleJoin} disabled={isJoining}>{isJoining ? 'Joining...' : 'Join'}</Button>
}
</div>
{isExpand && roomInfo.topic && <Text variant="b2">{twemojify(roomInfo.topic, undefined, true)}</Text>}
{isExpand && roomInfo.topic && <Text variant="b2">{twemojify(roomInfo.topic)}</Text>}
</div>
);
}

View file

@ -57,7 +57,6 @@ function StickerBoard({ roomId, onSelect }) {
alt={sticker.shortcode}
title={sticker.body ?? sticker.shortcode}
data-mx-sticker={sticker.mxc}
loading="lazy"
/>
))}
</div>

View file

@ -20,7 +20,7 @@ class Settings extends EventEmitter {
constructor() {
super();
this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme'];
this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme', 'nord-dark-theme', 'cyberpunk', 'almond-dark'];
this.themeIndex = this.getThemeIndex();
this.useSystemTheme = this.getUseSystemTheme();

View file

@ -1,14 +1,13 @@
@use './app/partials/screen';
:root {
/* background color | --bg-[background type]: value */
--bg-surface: #FFFFFF;
--bg-surface-transparent: #FFFFFF00;
--bg-surface-low: #F6F6F6;
--bg-surface-low-transparent: #F6F6F600;
--bg-surface-extra-low: #F6F6F6;
--bg-surface-extra-low-transparent: #F6F6F600;
--bg-surface: #ffffff;
--bg-surface-transparent: #ffffff00;
--bg-surface-low: #f6f6f6;
--bg-surface-low-transparent: #f6f6f600;
--bg-surface-extra-low: #f6f6f6;
--bg-surface-extra-low-transparent: #f6f6f600;
--bg-surface-hover: rgba(0, 0, 0, 3%);
--bg-surface-active: rgba(0, 0, 0, 5%);
--bg-surface-border: rgba(0, 0, 0, 6%);
@ -22,7 +21,7 @@
--bg-positive-hover: rgba(69, 184, 59, 8%);
--bg-positive-active: rgba(69, 184, 59, 15%);
--bg-positive-border: rgba(69, 184, 59, 40%);
--bg-caution: rgb(255, 179, 0);
--bg-caution-hover: rgba(255, 179, 0, 8%);
--bg-caution-active: rgba(255, 179, 0, 15%);
@ -37,18 +36,18 @@
--bg-badge: #989898;
--bg-ping: hsla(137deg, 100%, 68%, 40%);
--bg-ping-hover: hsla(137deg, 100%, 68%, 50%);
--bg-divider: hsla(0, 0%, 0%, .1);
--bg-divider: hsla(0, 0%, 0%, 0.1);
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: #000000;
--tc-surface-normal: rgba(0, 0, 0, 78%);
--tc-surface-normal-low: rgba(0, 0, 0, 60%);
--tc-surface-low: rgba(0, 0, 0, 48%);
--tc-primary-high: #ffffff;
--tc-primary-normal: rgba(255, 255, 255, 68%);
--tc-primary-low: rgba(255, 255, 255, 40%);
--tc-positive-high: var(--bg-positive);
--tc-positive-normal: rgb(69, 184, 59, 80%);
--tc-positive-low: rgb(69, 184, 59, 60%);
@ -56,7 +55,7 @@
--tc-caution-high: var(--bg-caution);
--tc-caution-normal: rgb(255, 179, 0, 80%);
--tc-caution-low: rgb(255, 179, 0, 60%);
--tc-danger-high: var(--bg-danger);
--tc-danger-normal: rgba(240, 71, 71, 88%);
--tc-danger-low: rgba(240, 71, 71, 60%);
@ -66,7 +65,6 @@
--tc-tooltip: white;
--tc-badge: white;
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: #272727;
--ic-surface-normal: #626262;
@ -102,7 +100,6 @@
--av-small: 36px;
--av-extra-small: 24px;
/* shadow and overlay */
--bg-overlay: rgba(0, 0, 0, 20%);
--bg-overlay-low: rgba(0, 0, 0, 50%);
@ -124,11 +121,9 @@
--bs-danger-border: inset 0 0 0 1px var(--bg-danger-border);
--bs-danger-outline: 0 0 0 2px var(--bg-danger-border);
/* border */
--bo-radius: 8px;
/* font styles: font-size, letter-spacing, line-hight */
--fs-h1: 36px;
--ls-h1: -1.5px;
@ -160,7 +155,6 @@
--fw-medium: 500;
--fw-bold: 700;
/* spacing | --sp-[space]: value */
--sp-none: 0px;
--sp-ultra-tight: 4px;
@ -170,7 +164,6 @@
--sp-loose: 20px;
--sp-extra-loose: 32px;
/* other */
--border-width: 1px;
--header-height: 54px;
@ -180,7 +173,7 @@
--people-drawer-width: calc(268px - var(--border-width));
--popup-window-drawer-width: 280px;
@include screen.smallerThan(tabletBreakpoint) {
--navigation-drawer-width: calc(240px + var(--border-width));
--people-drawer-width: calc(256px - var(--border-width));
@ -191,12 +184,11 @@
--fluid-push: cubic-bezier(0, 0.8, 0.67, 0.97);
--fluid-slide-down: cubic-bezier(0.02, 0.82, 0.4, 0.96);
--fluid-slide-up: cubic-bezier(0.13, 0.56, 0.25, 0.99);
--font-primary: 'Roboto', sans-serif;
--font-secondary: 'Roboto', sans-serif;
}
.silver-theme {
/* background color | --bg-[background type]: value */
--bg-surface: hsl(0, 0%, 95%);
@ -228,15 +220,14 @@
--bg-badge: hsl(0, 0%, 75%);
--bg-ping: hsla(137deg, 100%, 38%, 40%);
--bg-ping-hover: hsla(137deg, 100%, 38%, 50%);
--bg-divider: hsla(0, 0%, 100%, .1);
--bg-divider: hsla(0, 0%, 100%, 0.1);
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgba(255, 255, 255, 98%);
--tc-surface-normal: rgba(255, 255, 255, 94%);
--tc-surface-normal-low: rgba(255, 255, 255, 60%);
--tc-surface-low: rgba(255, 255, 255, 58%);
--tc-primary-high: #ffffff;
--tc-primary-normal: rgba(255, 255, 255, 0.68);
--tc-primary-low: rgba(255, 255, 255, 0.4);
@ -262,7 +253,7 @@
--mx-uc-7: hsl(243, 100%, 74%);
--mx-uc-8: hsl(94, 66%, 50%);
}
/* shadow and overlay */
--bg-overlay: rgba(0, 0, 0, 60%);
--bg-overlay-low: rgba(0, 0, 0, 80%);
@ -274,7 +265,7 @@
--bs-primary-border: inset 0 0 0 1px var(--bg-primary-border);
--bs-primary-outline: 0 0 0 2px var(--bg-primary-border);
/* font styles: font-size, letter-spacing, line-hight */
--fs-h1: 35.6px;
@ -296,7 +287,10 @@
}
.dark-theme,
.butter-theme {
.butter-theme,
.nord-dark-theme,
.cyberpunk,
.almond-dark {
@include dark-mode();
}
@ -317,20 +311,105 @@
--bg-badge: #c4c1ab;
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgb(255, 251, 222, 94%);
--tc-surface-normal: rgba(255, 251, 222, 94%);
--tc-surface-normal-low: rgba(255, 251, 222, 60%);
--tc-surface-normal-low: rgba(255, 251, 222, 60%);
--tc-surface-low: rgba(255, 251, 222, 58%);
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: rgb(255, 251, 222);
--ic-surface-normal: rgba(255, 251, 222, 84%);
--ic-surface-low: rgba(255, 251, 222, 64%);
}
.nord-dark-theme {
/* background color | --bg-[background type]: value */
--bg-surface: hsl(220, 16%, 22%);
--bg-surface-transparent: hsl(220, 16%, 22%, 0%);
--bg-surface-low: hsl(222, 16%, 28%);
--bg-surface-low-transparent: hsl(222, 16%, 28%, 0%);
--bg-surface-extra-low: hsl(220, 17%, 32%);
--bg-surface-extra-low-transparent: hsl(220, 17%, 32%, 0%);
--bg-badge: #5e81ac;
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgba(216, 222, 233, 94%);
--tc-surface-normal: rgba(216, 222, 233, 94%);
--tc-surface-normal-low: rgba(216, 222, 233, 60%);
--tc-surface-low: rgba(216, 222, 233, 58%);
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: rgb(216, 222, 233);
--ic-surface-normal: rgba(216, 222, 233, 84%);
--ic-surface-low: rgba(216, 222, 233, 64%);
}
.cyberpunk {
/* background color | --bg-[background type]: value */
--bg-surface: hsl(0, 0%, 0%);
--bg-surface-transparent: hsla(0, 0%, 0%, 0);
--bg-surface-low: hsl(0, 0%, 0%);
--bg-surface-low-transparent: hsla(0, 0%, 0%, 0);
--bg-surface-extra-low: hsl(58, 98%, 49%);
--bg-surface-extra-low-transparent: hsla(0, 0%, 0%, 0);
--bg-badge: hsl(346, 100%, 50%);
--bg-positive: hsl(346, 100%, 50%);
--bg-positive-hover: hsl(346, 100%, 50%, 8%);
--bg-positive-active: hsl(346, 100%, 50%, 15%);
--bg-positive-border: hsl(346, 100%, 50%, 40%);
--bg-primary: hsl(346, 100%, 50%);
--bg-primary-hover: hsl(346, 100%, 50%, 8%);
--bg-primary-active: hsl(346, 100%, 50%, 15%);
--bg-primary-border: hsl(346, 100%, 50%, 40%);
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgb(249, 240, 2, 94%);
--tc-surface-normal: rgba(255, 251, 222, 94%);
--tc-surface-normal-low: rgba(255, 251, 222, 94%);
--tc-surface-low: rgba(255, 251, 222, 58%);
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: rgb(255, 251, 222);
--ic-surface-normal: rgba(255, 251, 222, 84%);
--ic-surface-low: rgba(255, 251, 222, 64%);
}
.almond-dark {
/* background color | --bg-[background type]: value */
--bg-surface: hsl(0, 0%, 0%);
--bg-surface-transparent: hsla(0, 0%, 0%, 0);
--bg-surface-low: hsl(0, 0%, 1%);
--bg-surface-low-transparent: hsla(0, 0%, 0%, 0);
--bg-surface-extra-low: hsl(0, 0%, 2%);
--bg-surface-extra-low-transparent: hsla(0, 0%, 0%, 0);
--bg-badge: rgb(255, 251, 222, 90%);
--bg-positive: rgb(255, 251, 222, 90%);
--bg-positive-hover: rgba(255, 251, 222, 8%);
--bg-positive-active: rgba(255, 251, 222, 15%);
--bg-positive-border: rgba(255, 251, 222, 40%);
--bg-primary: rgb(255, 251, 222, 90%);
--bg-primary-hover: rgba(255, 251, 222, 8%);
--bg-primary-active: rgba(255, 251, 222, 15%);
--bg-primary-border: rgba(255, 251, 222, 40%);
/* text color | --tc-[background type]-[priority]: value */
--tc-surface-high: rgb(255, 251, 222, 90%);
--tc-surface-normal: rgba(255, 251, 222, 90%);
--tc-surface-normal-low: rgba(255, 251, 222, 60%);
--tc-surface-low: rgba(255, 251, 222, 30%);
/* system icons | --ic-[background type]-[priority]: value */
--ic-surface-high: rgb(255, 251, 222, 90%);
--ic-surface-normal: rgba(255, 251, 222, 60%);
--ic-surface-low: rgba(255, 251, 222, 30%);
}
.font-primary {
font-family: var(--font-primary);
@ -387,9 +466,11 @@ body {
height: 100%;
}
*, *::before, *::after {
*,
*::before,
*::after {
box-sizing: border-box;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-tap-highlight-color: transparent;
}
a {
@ -428,16 +509,16 @@ button {
textarea,
input,
input[type],
input[type=text],
input[type=username],
input[type=password],
input[type=email],
input[type=checkbox] {
input[type='text'],
input[type='username'],
input[type='password'],
input[type='email'],
input[type='checkbox'] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input[type=checkbox] {
input[type='checkbox'] {
margin: 0;
padding: 0;
width: 20px;
@ -451,7 +532,7 @@ input[type=checkbox] {
&:checked {
background-color: var(--bg-primary);
&::before {
content: "";
content: '';
display: inline-block;
width: 12px;
height: 6px;
@ -468,11 +549,11 @@ textarea {
}
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
@ -484,4 +565,4 @@ audio:not([controls]) {
display: flex;
justify-content: center;
align-items: center;
}
}

View file

@ -30,26 +30,21 @@ const mathOptions = {
};
/**
* @param {string} text - text to twemojify
* @param {object|undefined} opts - options for tweomoji.parse
* @param {boolean} [linkify=false] - convert links to html tags (default: false)
* @param {string} text - text
* @param {undefined} opts
* @param {boolean} [linkify=true] - convert links to html tags (default: true)
* @param {boolean} [sanitize=true] - sanitize html text (default: true)
* @param {boolean} [maths=false] - render maths (default: false)
* @param {boolean} [maths=true] - render maths (default: true)
* @returns React component
*/
export function twemojify(text, opts, linkify = false, sanitize = true, maths = false) {
export function twemojify(text, opts, linkify = true, sanitize = true, maths = true) {
if (typeof text !== 'string') return text;
let content = text;
const options = opts ?? { base: TWEMOJI_BASE_URL };
if (!options.base) {
options.base = TWEMOJI_BASE_URL;
}
if (sanitize) {
content = sanitizeText(content);
}
content = twemoji.parse(content, options);
if (linkify) {
content = linkifyHtml(content, {
target: '_blank',