mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +03:00 
			
		
		
		
	Timeline-refactor-fixes (#1438)
* fix type * fix missing member from reaction * stop context menu event propagation in msg modal * prevent encode blur hash from freezing app * replace roboto font with inter and fix weight * add recent emoji when selecting emoji * fix room latest evt hook * add option to drop typing status
This commit is contained in:
		
							parent
							
								
									f9b895b32c
								
							
						
					
					
						commit
						1bdb7f4e3a
					
				
					 18 changed files with 138 additions and 64 deletions
				
			
		
							
								
								
									
										6
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -10,7 +10,6 @@
 | 
			
		|||
      "license": "AGPL-3.0-only",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@fontsource/inter": "4.5.14",
 | 
			
		||||
        "@fontsource/roboto": "4.5.8",
 | 
			
		||||
        "@khanacademy/simple-markdown": "0.8.6",
 | 
			
		||||
        "@matrix-org/olm": "3.2.14",
 | 
			
		||||
        "@tanstack/react-virtual": "3.0.0-beta.54",
 | 
			
		||||
| 
						 | 
				
			
			@ -875,11 +874,6 @@
 | 
			
		|||
      "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-4.5.14.tgz",
 | 
			
		||||
      "integrity": "sha512-JDC9AocdPLuGsASkvWw9hS5gtHE7K9dOwL98XLrk5yjYqxy4uVnScG58NUvFMJDVJRl/7c8Wnap6PEs+7Zvj1Q=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@fontsource/roboto": {
 | 
			
		||||
      "version": "4.5.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz",
 | 
			
		||||
      "integrity": "sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@humanwhocodes/config-array": {
 | 
			
		||||
      "version": "0.11.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,6 @@
 | 
			
		|||
  "license": "AGPL-3.0-only",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@fontsource/inter": "4.5.14",
 | 
			
		||||
    "@fontsource/roboto": "4.5.8",
 | 
			
		||||
    "@khanacademy/simple-markdown": "0.8.6",
 | 
			
		||||
    "@matrix-org/olm": "3.2.14",
 | 
			
		||||
    "@tanstack/react-virtual": "3.0.0-beta.54",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ import { editableActiveElement, isIntersectingScrollView, targetFromEvent } from
 | 
			
		|||
import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch';
 | 
			
		||||
import { useDebounce } from '../../hooks/useDebounce';
 | 
			
		||||
import { useThrottle } from '../../hooks/useThrottle';
 | 
			
		||||
import { addRecentEmoji } from '../../plugins/recent-emoji';
 | 
			
		||||
 | 
			
		||||
const RECENT_GROUP_ID = 'recent_group';
 | 
			
		||||
const SEARCH_GROUP_ID = 'search_group';
 | 
			
		||||
| 
						 | 
				
			
			@ -697,7 +698,10 @@ export function EmojiBoard({
 | 
			
		|||
    if (!emojiInfo) return;
 | 
			
		||||
    if (emojiInfo.type === EmojiType.Emoji) {
 | 
			
		||||
      onEmojiSelect?.(emojiInfo.data, emojiInfo.shortcode);
 | 
			
		||||
      if (!evt.altKey && !evt.shiftKey) requestClose();
 | 
			
		||||
      if (!evt.altKey && !evt.shiftKey) {
 | 
			
		||||
        addRecentEmoji(mx, emojiInfo.data);
 | 
			
		||||
        requestClose();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (emojiInfo.type === EmojiType.CustomEmoji) {
 | 
			
		||||
      onCustomEmojiSelect?.(emojiInfo.data, emojiInfo.shortcode);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,29 +0,0 @@
 | 
			
		|||
import { MatrixEvent, Room, RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
 | 
			
		||||
import { useEffect, useState } from 'react';
 | 
			
		||||
 | 
			
		||||
export const useRoomLatestEvent = (room: Room) => {
 | 
			
		||||
  const [latestEvent, setLatestEvent] = useState<MatrixEvent>();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getLatestEvent = (): MatrixEvent | undefined => {
 | 
			
		||||
      const liveEvents = room.getLiveTimeline().getEvents();
 | 
			
		||||
      for (let i = liveEvents.length - 1; i >= 0; i -= 1) {
 | 
			
		||||
        const evt = liveEvents[i];
 | 
			
		||||
        if (evt) return evt;
 | 
			
		||||
      }
 | 
			
		||||
      return undefined;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleTimelineEvent: RoomEventHandlerMap[RoomEvent.Timeline] = () => {
 | 
			
		||||
      setLatestEvent(getLatestEvent());
 | 
			
		||||
    };
 | 
			
		||||
    setLatestEvent(getLatestEvent());
 | 
			
		||||
 | 
			
		||||
    room.on(RoomEvent.Timeline, handleTimelineEvent);
 | 
			
		||||
    return () => {
 | 
			
		||||
      room.removeListener(RoomEvent.Timeline, handleTimelineEvent);
 | 
			
		||||
    };
 | 
			
		||||
  }, [room]);
 | 
			
		||||
 | 
			
		||||
  return latestEvent;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										57
									
								
								src/app/hooks/useRoomLatestRenderedEvent.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/app/hooks/useRoomLatestRenderedEvent.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,57 @@
 | 
			
		|||
/* eslint-disable no-continue */
 | 
			
		||||
import { MatrixEvent, Room, RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
 | 
			
		||||
import { useEffect, useState } from 'react';
 | 
			
		||||
import { settingsAtom } from '../state/settings';
 | 
			
		||||
import { useSetting } from '../state/hooks/settings';
 | 
			
		||||
import { MessageEvent, StateEvent } from '../../types/matrix/room';
 | 
			
		||||
 | 
			
		||||
export const useRoomLatestRenderedEvent = (room: Room) => {
 | 
			
		||||
  const [hideMembershipEvents] = useSetting(settingsAtom, 'hideMembershipEvents');
 | 
			
		||||
  const [hideNickAvatarEvents] = useSetting(settingsAtom, 'hideNickAvatarEvents');
 | 
			
		||||
  const [showHiddenEvents] = useSetting(settingsAtom, 'showHiddenEvents');
 | 
			
		||||
  const [latestEvent, setLatestEvent] = useState<MatrixEvent>();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const getLatestEvent = (): MatrixEvent | undefined => {
 | 
			
		||||
      const liveEvents = room.getLiveTimeline().getEvents();
 | 
			
		||||
      for (let i = liveEvents.length - 1; i >= 0; i -= 1) {
 | 
			
		||||
        const evt = liveEvents[i];
 | 
			
		||||
 | 
			
		||||
        if (!evt) continue;
 | 
			
		||||
        if (evt.isRelation()) continue;
 | 
			
		||||
        if (evt.getType() === StateEvent.RoomMember) {
 | 
			
		||||
          const membershipChanged = evt.getContent().membership !== evt.getPrevContent().membership;
 | 
			
		||||
          if (membershipChanged && hideMembershipEvents) continue;
 | 
			
		||||
          if (!membershipChanged && hideNickAvatarEvents) continue;
 | 
			
		||||
          return evt;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (
 | 
			
		||||
          evt.getType() === MessageEvent.RoomMessage ||
 | 
			
		||||
          evt.getType() === MessageEvent.RoomMessageEncrypted ||
 | 
			
		||||
          evt.getType() === MessageEvent.Sticker ||
 | 
			
		||||
          evt.getType() === StateEvent.RoomName ||
 | 
			
		||||
          evt.getType() === StateEvent.RoomTopic ||
 | 
			
		||||
          evt.getType() === StateEvent.RoomAvatar
 | 
			
		||||
        ) {
 | 
			
		||||
          return evt;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (showHiddenEvents) return evt;
 | 
			
		||||
      }
 | 
			
		||||
      return undefined;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleTimelineEvent: RoomEventHandlerMap[RoomEvent.Timeline] = () => {
 | 
			
		||||
      setLatestEvent(getLatestEvent());
 | 
			
		||||
    };
 | 
			
		||||
    setLatestEvent(getLatestEvent());
 | 
			
		||||
 | 
			
		||||
    room.on(RoomEvent.Timeline, handleTimelineEvent);
 | 
			
		||||
    return () => {
 | 
			
		||||
      room.removeListener(RoomEvent.Timeline, handleTimelineEvent);
 | 
			
		||||
    };
 | 
			
		||||
  }, [room, hideMembershipEvents, hideNickAvatarEvents, showHiddenEvents]);
 | 
			
		||||
 | 
			
		||||
  return latestEvent;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +167,7 @@ export const getFirstLinkedTimeline = (
 | 
			
		|||
 | 
			
		||||
export const getLinkedTimelines = (timeline: EventTimeline): EventTimeline[] => {
 | 
			
		||||
  const firstTimeline = getFirstLinkedTimeline(timeline, Direction.Backward);
 | 
			
		||||
  const timelines = [];
 | 
			
		||||
  const timelines: EventTimeline[] = [];
 | 
			
		||||
 | 
			
		||||
  for (
 | 
			
		||||
    let nextTimeline: EventTimeline | null = firstTimeline;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ import { getMemberDisplayName } from '../../utils/room';
 | 
			
		|||
import { getMxIdLocalPart } from '../../utils/matrix';
 | 
			
		||||
import * as css from './RoomViewFollowing.css';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
import { useRoomLatestEvent } from '../../hooks/useRoomLatestEvent';
 | 
			
		||||
import { useRoomLatestRenderedEvent } from '../../hooks/useRoomLatestRenderedEvent';
 | 
			
		||||
import { useRoomEventReaders } from '../../hooks/useRoomEventReaders';
 | 
			
		||||
import { EventReaders } from '../../components/event-readers';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ export const RoomViewFollowing = as<'div', RoomViewFollowingProps>(
 | 
			
		|||
  ({ className, room, ...props }, ref) => {
 | 
			
		||||
    const mx = useMatrixClient();
 | 
			
		||||
    const [open, setOpen] = useState(false);
 | 
			
		||||
    const latestEvent = useRoomLatestEvent(room);
 | 
			
		||||
    const latestEvent = useRoomLatestRenderedEvent(room);
 | 
			
		||||
    const latestEventReaders = useRoomEventReaders(room, latestEvent?.getId());
 | 
			
		||||
    const followingMembers = latestEventReaders
 | 
			
		||||
      .map((readerId) => room.getMember(readerId))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,3 +22,6 @@ export const RoomViewTyping = style([
 | 
			
		|||
    animation: `${SlideUpAnime} 100ms ease-in-out`,
 | 
			
		||||
  },
 | 
			
		||||
]);
 | 
			
		||||
export const TypingText = style({
 | 
			
		||||
  flexGrow: 1,
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import React, { useMemo } from 'react';
 | 
			
		||||
import { Box, Text, as } from 'folds';
 | 
			
		||||
import { Box, Icon, IconButton, Icons, Text, as } from 'folds';
 | 
			
		||||
import { Room } from 'matrix-js-sdk';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { useAtomValue } from 'jotai';
 | 
			
		||||
import { useAtomValue, useSetAtom } from 'jotai';
 | 
			
		||||
import { roomIdToTypingMembersAtom, selectRoomTypingMembersAtom } from '../../state/typingMembers';
 | 
			
		||||
import { TypingIndicator } from '../../components/typing-indicator';
 | 
			
		||||
import { getMemberDisplayName } from '../../utils/room';
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +15,7 @@ export type RoomViewTypingProps = {
 | 
			
		|||
};
 | 
			
		||||
export const RoomViewTyping = as<'div', RoomViewTypingProps>(
 | 
			
		||||
  ({ className, room, ...props }, ref) => {
 | 
			
		||||
    const setTypingMembers = useSetAtom(roomIdToTypingMembersAtom);
 | 
			
		||||
    const mx = useMatrixClient();
 | 
			
		||||
    const typingMembers = useAtomValue(
 | 
			
		||||
      useMemo(() => selectRoomTypingMembersAtom(room.roomId, roomIdToTypingMembersAtom), [room])
 | 
			
		||||
| 
						 | 
				
			
			@ -29,6 +30,18 @@ export const RoomViewTyping = as<'div', RoomViewTypingProps>(
 | 
			
		|||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const handleDropAll = () => {
 | 
			
		||||
      // some homeserver does not timeout typing status
 | 
			
		||||
      // we have given option so user can drop their typing status
 | 
			
		||||
      typingMembers.forEach((member) =>
 | 
			
		||||
        setTypingMembers({
 | 
			
		||||
          type: 'DELETE',
 | 
			
		||||
          roomId: room.roomId,
 | 
			
		||||
          member,
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <Box
 | 
			
		||||
        className={classNames(css.RoomViewTyping, className)}
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +51,7 @@ export const RoomViewTyping = as<'div', RoomViewTypingProps>(
 | 
			
		|||
        ref={ref}
 | 
			
		||||
      >
 | 
			
		||||
        <TypingIndicator />
 | 
			
		||||
        <Text size="T300" truncate>
 | 
			
		||||
        <Text className={css.TypingText} size="T300" truncate>
 | 
			
		||||
          {typingNames.length === 1 && (
 | 
			
		||||
            <>
 | 
			
		||||
              <b>{typingNames[0]}</b>
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +109,9 @@ export const RoomViewTyping = as<'div', RoomViewTypingProps>(
 | 
			
		|||
            </>
 | 
			
		||||
          )}
 | 
			
		||||
        </Text>
 | 
			
		||||
        <IconButton title="Drop Typing Status" size="300" radii="Pill" onClick={handleDropAll}>
 | 
			
		||||
          <Icon size="50" src={Icons.Cross} />
 | 
			
		||||
        </IconButton>
 | 
			
		||||
      </Box>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,7 +94,7 @@ function ReadTextFile({ body, mimeType, url, encInfo }: Omit<FileContentProps, '
 | 
			
		|||
                clickOutsideDeactivates: true,
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              <Modal size="500">
 | 
			
		||||
              <Modal size="500" onContextMenu={(evt: any) => evt.stopPropagation()}>
 | 
			
		||||
                <TextViewer
 | 
			
		||||
                  name={body}
 | 
			
		||||
                  text={textState.data}
 | 
			
		||||
| 
						 | 
				
			
			@ -159,7 +159,7 @@ function ReadPdfFile({ body, mimeType, url, encInfo }: Omit<FileContentProps, 'i
 | 
			
		|||
                clickOutsideDeactivates: true,
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              <Modal size="500">
 | 
			
		||||
              <Modal size="500" onContextMenu={(evt: any) => evt.stopPropagation()}>
 | 
			
		||||
                <PdfViewer
 | 
			
		||||
                  name={body}
 | 
			
		||||
                  src={pdfState.data}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,7 @@ export const ImageContent = as<'div', ImageContentProps>(
 | 
			
		|||
                  clickOutsideDeactivates: true,
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <Modal size="500">
 | 
			
		||||
                <Modal size="500" onContextMenu={(evt: any) => evt.stopPropagation()}>
 | 
			
		||||
                  <ImageViewer
 | 
			
		||||
                    src={srcState.data}
 | 
			
		||||
                    alt={body}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ import {
 | 
			
		|||
import { encryptFile, getImageInfo, getThumbnailContent, getVideoInfo } from '../../utils/matrix';
 | 
			
		||||
import { TUploadItem } from '../../state/roomInputDrafts';
 | 
			
		||||
import { encodeBlurHash } from '../../utils/blurHash';
 | 
			
		||||
import { scaleYDimension } from '../../utils/common';
 | 
			
		||||
 | 
			
		||||
const generateThumbnailContent = async (
 | 
			
		||||
  mx: MatrixClient,
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +53,7 @@ export const getImageMsgContent = async (
 | 
			
		|||
    body: file.name,
 | 
			
		||||
  };
 | 
			
		||||
  if (imgEl) {
 | 
			
		||||
    const blurHash = encodeBlurHash(imgEl);
 | 
			
		||||
    const blurHash = encodeBlurHash(imgEl, 512, scaleYDimension(imgEl.width, 512, imgEl.height));
 | 
			
		||||
    const [thumbError, thumbContent] = await to(
 | 
			
		||||
      generateThumbnailContent(
 | 
			
		||||
        mx,
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +108,11 @@ export const getVideoMsgContent = async (
 | 
			
		|||
      )
 | 
			
		||||
    );
 | 
			
		||||
    if (thumbContent && thumbContent.thumbnail_info) {
 | 
			
		||||
      thumbContent.thumbnail_info[MATRIX_BLUR_HASH_PROPERTY_NAME] = encodeBlurHash(videoEl);
 | 
			
		||||
      thumbContent.thumbnail_info[MATRIX_BLUR_HASH_PROPERTY_NAME] = encodeBlurHash(
 | 
			
		||||
        videoEl,
 | 
			
		||||
        512,
 | 
			
		||||
        scaleYDimension(videoEl.videoWidth, 512, videoEl.videoHeight)
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    if (thumbError) console.warn(thumbError);
 | 
			
		||||
    content.info = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,10 +99,9 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
			
		|||
                  const senderId = mEvent.getSender();
 | 
			
		||||
                  if (!senderId) return null;
 | 
			
		||||
                  const member = room.getMember(senderId);
 | 
			
		||||
                  if (!member) return null;
 | 
			
		||||
                  const name = getName(member);
 | 
			
		||||
                  const name = (member ? getName(member) : getMxIdLocalPart(senderId)) ?? senderId;
 | 
			
		||||
 | 
			
		||||
                  const avatarUrl = member.getAvatarUrl(
 | 
			
		||||
                  const avatarUrl = member?.getAvatarUrl(
 | 
			
		||||
                    mx.baseUrl,
 | 
			
		||||
                    100,
 | 
			
		||||
                    100,
 | 
			
		||||
| 
						 | 
				
			
			@ -113,12 +112,12 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
			
		|||
 | 
			
		||||
                  return (
 | 
			
		||||
                    <MenuItem
 | 
			
		||||
                      key={member.userId}
 | 
			
		||||
                      key={senderId}
 | 
			
		||||
                      style={{ padding: `0 ${config.space.S200}` }}
 | 
			
		||||
                      radii="400"
 | 
			
		||||
                      onClick={() => {
 | 
			
		||||
                        requestClose();
 | 
			
		||||
                        openProfileViewer(member.userId, room.roomId);
 | 
			
		||||
                        openProfileViewer(senderId, room.roomId);
 | 
			
		||||
                      }}
 | 
			
		||||
                      before={
 | 
			
		||||
                        <Avatar size="200">
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +126,7 @@ export const ReactionViewer = as<'div', ReactionViewerProps>(
 | 
			
		|||
                          ) : (
 | 
			
		||||
                            <AvatarFallback
 | 
			
		||||
                              style={{
 | 
			
		||||
                                background: colorMXID(member.userId),
 | 
			
		||||
                                background: colorMXID(senderId),
 | 
			
		||||
                                color: 'white',
 | 
			
		||||
                              }}
 | 
			
		||||
                            >
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ import appDispatcher from '../dispatcher';
 | 
			
		|||
 | 
			
		||||
import cons from './cons';
 | 
			
		||||
import { darkTheme, butterTheme, silverTheme } from '../../colors.css';
 | 
			
		||||
import { onLightFontWeight, onDarkFontWeight } from '../../config.css';
 | 
			
		||||
 | 
			
		||||
function getSettings() {
 | 
			
		||||
  const settings = localStorage.getItem('settings');
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +24,7 @@ class Settings extends EventEmitter {
 | 
			
		|||
    super();
 | 
			
		||||
 | 
			
		||||
    this.themeClasses = [lightTheme, silverTheme, darkTheme, butterTheme];
 | 
			
		||||
    this.fontWeightClasses = [onLightFontWeight, onLightFontWeight, onDarkFontWeight, onDarkFontWeight]
 | 
			
		||||
    this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme'];
 | 
			
		||||
    this.themeIndex = this.getThemeIndex();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -59,6 +61,7 @@ class Settings extends EventEmitter {
 | 
			
		|||
    this.themes.forEach((themeName, index) => {
 | 
			
		||||
      if (themeName !== '') document.body.classList.remove(themeName);
 | 
			
		||||
      document.body.classList.remove(this.themeClasses[index]);
 | 
			
		||||
      document.body.classList.remove(this.fontWeightClasses[index]);
 | 
			
		||||
      document.body.classList.remove('prism-light')
 | 
			
		||||
      document.body.classList.remove('prism-dark')
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +74,7 @@ class Settings extends EventEmitter {
 | 
			
		|||
    if (this.themes[themeIndex] === undefined) return
 | 
			
		||||
    if (this.themes[themeIndex]) document.body.classList.add(this.themes[themeIndex]);
 | 
			
		||||
    document.body.classList.add(this.themeClasses[themeIndex]);
 | 
			
		||||
    document.body.classList.add(this.fontWeightClasses[themeIndex]);
 | 
			
		||||
    document.body.classList.add(themeIndex < 2 ? 'prism-light' : 'prism-dark');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								src/config.css.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/config.css.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
import { createTheme } from '@vanilla-extract/css';
 | 
			
		||||
import { config } from 'folds';
 | 
			
		||||
 | 
			
		||||
export const onLightFontWeight = createTheme(config.fontWeight, {
 | 
			
		||||
  W100: '100',
 | 
			
		||||
  W200: '200',
 | 
			
		||||
  W300: '300',
 | 
			
		||||
  W400: '420',
 | 
			
		||||
  W500: '500',
 | 
			
		||||
  W600: '600',
 | 
			
		||||
  W700: '700',
 | 
			
		||||
  W800: '800',
 | 
			
		||||
  W900: '900',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const onDarkFontWeight = createTheme(config.fontWeight, {
 | 
			
		||||
  W100: '100',
 | 
			
		||||
  W200: '200',
 | 
			
		||||
  W300: '300',
 | 
			
		||||
  W400: '350',
 | 
			
		||||
  W500: '450',
 | 
			
		||||
  W600: '550',
 | 
			
		||||
  W700: '650',
 | 
			
		||||
  W800: '750',
 | 
			
		||||
  W900: '850',
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +0,0 @@
 | 
			
		|||
import '@fontsource/roboto/300.css';
 | 
			
		||||
import '@fontsource/roboto/400.css';
 | 
			
		||||
import '@fontsource/roboto/500.css';
 | 
			
		||||
import '@fontsource/roboto/700.css';
 | 
			
		||||
import '@fontsource/inter/variable.css';
 | 
			
		||||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ import { configClass, varsClass } from 'folds';
 | 
			
		|||
 | 
			
		||||
enableMapSet();
 | 
			
		||||
 | 
			
		||||
import './font';
 | 
			
		||||
import './index.scss';
 | 
			
		||||
 | 
			
		||||
import settings from './client/state/settings';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,7 +158,7 @@
 | 
			
		|||
 | 
			
		||||
  /* font-weight */
 | 
			
		||||
  --fw-light: 300;
 | 
			
		||||
  --fw-normal: 400;
 | 
			
		||||
  --fw-normal: 420;
 | 
			
		||||
  --fw-medium: 500;
 | 
			
		||||
  --fw-bold: 700;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -193,8 +193,8 @@
 | 
			
		|||
  --fluid-slide-up: cubic-bezier(0.13, 0.56, 0.25, 0.99);
 | 
			
		||||
 | 
			
		||||
  --font-emoji: 'Twemoji';
 | 
			
		||||
  --font-primary: 'Roboto', var(--font-emoji), sans-serif;
 | 
			
		||||
  --font-secondary: 'Roboto', var(--font-emoji), sans-serif;
 | 
			
		||||
  --font-primary: 'InterVariable', var(--font-emoji), sans-serif;
 | 
			
		||||
  --font-secondary: 'InterVariable', var(--font-emoji), sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.silver-theme {
 | 
			
		||||
| 
						 | 
				
			
			@ -291,8 +291,10 @@
 | 
			
		|||
 | 
			
		||||
  /* override normal font weight for dark mode */
 | 
			
		||||
  --fw-normal: 350;
 | 
			
		||||
  --fw-medium: 450;
 | 
			
		||||
  --fw-bold: 550;
 | 
			
		||||
 | 
			
		||||
  --font-secondary: 'InterVariable', 'Roboto', var(--font-emoji), sans-serif;
 | 
			
		||||
  --font-secondary: 'InterVariable', var(--font-emoji), sans-serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.butter-theme {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue