12 Commits

Author SHA1 Message Date
trashtemp
bba9689e30 fix(settings): small bug fixes 2021-12-24 14:26:07 +01:00
trashtemp
cc76e78db8 fix(settings): started work on settings cleanup 2021-12-23 17:35:58 +00:00
trashtemp
d2d7083542 fix(home,settings): updated homepage, settings
* new home screen
* cleaned up settings
2021-12-23 17:29:35 +00:00
Paul
73d99e4518 feat(home): add snow 2021-12-23 13:16:43 +00:00
Paul
f14ef2b78f chore: pull languages 2021-12-22 22:11:32 +00:00
Paul
4719150368 feat(renderer): add additional languages to cb
Closes #28
2021-12-22 22:11:25 +00:00
Paul
3d73834bef fix(server settings): unrestrict height 2021-12-22 10:36:23 +00:00
Paul Makles
1aff8ef516 chore(ci): only mirror master and production 2021-12-21 17:50:46 +00:00
Paul Makles
b80a6a9c3e chore(ci): remove preview PR workflow (#452) 2021-12-21 17:50:08 +00:00
Paul Makles
1780d06c97 chore(ci): triage PR on synchronize 2021-12-21 17:47:14 +00:00
Paul Makles
c29efc155b chore(ci): update CI tasks to move PRs when updated 2021-12-21 17:37:59 +00:00
Paul
71c0a782c1 fix(notifications): use effective name and avatar for notif 2021-12-21 12:38:53 +00:00
33 changed files with 757 additions and 395 deletions

View File

@@ -1,6 +1,10 @@
name: Mirroring name: Mirroring
on: [push, delete] on:
push:
branches:
- "master"
- "production"
jobs: jobs:
to_gitlab: to_gitlab:

View File

@@ -1,39 +0,0 @@
name: Clean Preview
#! Safety:
#! this workflow should not execute any untrusted input at all
#! see the docs on `pull_request_target` for more
on:
pull_request_target:
types: [unlabeled]
jobs:
clean:
runs-on: ubuntu-latest
if: github.event.label.name == 'use-preview'
env:
BASE: refs/pull/${{ github.event.pull_request.number }}
steps:
- uses: actions/checkout@v2
with:
ref: build-previews
persist-credentials: false
- name: clean previews
run: rm -rf "$BASE"
- name: publish cleaned previews
uses: JamesIves/github-pages-deploy-action@4.1.5
with:
folder: .
branch: build-previews
commit-message: "Cleaning up build result for #${{ github.event.pull_request.number }}"
- name: send comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: Preview environment
message: |
## Preview environment
There is no longer a preview enviroment for this pull request due to the `use-preview` label being removed

View File

@@ -1,52 +0,0 @@
name: Preview Pull Request
#! Safety:
#! this workflow should not execute any untrusted input at all
#! see the docs on `pull_request_target` for more
on:
pull_request_target:
types: [synchronize, reopened, labeled]
jobs:
preview:
runs-on: ubuntu-latest
# make sure the pull request is labeled with 'use-preview'
if: github.event.label.name == 'use-preview' || contains(github.event.pull_request.labels.*.name, 'use-preview')
env:
BASE: refs/pull/${{ github.event.pull_request.number }}/merge
REPO: ${{ github.event.repository.name }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2
with:
# Head commit of the pull request
ref: ${{ github.event.pull_request.head.sha }}
path: pull
submodules: recursive
- name: build
uses: ./.github/actions/build
with:
base: /${{ env.REPO }}/${{ env.BASE }}/
folder: pull
- name: publish preview
uses: JamesIves/github-pages-deploy-action@4.1.5
with:
folder: pull/dist
branch: build-previews
target-folder: ${{ env.BASE }}
single-commit: true
commit-message: "Publishing build result from #${{ github.event.pull_request.number }}"
- name: send comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: Preview environment
message: |
## Preview environment
https://${{ github.repository_owner }}.github.io/${{ env.REPO }}/${{ env.BASE }}/
This link will remain active until the `use-preview` label is removed.

View File

@@ -1,72 +1,72 @@
name: Add PR to Board name: Add PR to Board
on: on:
pull_request_target: pull_request_target:
types: [opened] types: [opened, synchronize, ready_for_review, review_requested]
jobs: jobs:
track_pr: track_pr:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Get project data - name: Get project data
env: env:
GITHUB_TOKEN: ${{ secrets.PAT }} GITHUB_TOKEN: ${{ secrets.PAT }}
run: | run: |
gh api graphql -f query=' gh api graphql -f query='
query { query {
organization(login: "revoltchat"){ organization(login: "revoltchat"){
projectNext(number: 3) { projectNext(number: 3) {
id id
fields(first:20) { fields(first:20) {
nodes { nodes {
id id
name name
settings settings
} }
} }
} }
} }
}' > project_data.json }' > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'INCOMING_OPTION_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") |.settings | fromjson.options[] | select(.name=="Incoming PRs") |.id' project_data.json) >> $GITHUB_ENV echo 'INCOMING_OPTION_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") |.settings | fromjson.options[] | select(.name=="Incoming PRs") |.id' project_data.json) >> $GITHUB_ENV
- name: Add PR to project - name: Add PR to project
env: env:
GITHUB_TOKEN: ${{ secrets.PAT }} GITHUB_TOKEN: ${{ secrets.PAT }}
PR_ID: ${{ github.event.pull_request.node_id }} PR_ID: ${{ github.event.pull_request.node_id }}
run: | run: |
item_id="$( gh api graphql -f query=' item_id="$( gh api graphql -f query='
mutation($project:ID!, $pr:ID!) { mutation($project:ID!, $pr:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $pr}) { addProjectNextItem(input: {projectId: $project, contentId: $pr}) {
projectNextItem { projectNextItem {
id id
} }
} }
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')" }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Set fields echo 'ITEM_ID='$item_id >> $GITHUB_ENV
env:
GITHUB_TOKEN: ${{ secrets.PAT }} - name: Set fields
run: | env:
gh api graphql -f query=' GITHUB_TOKEN: ${{ secrets.PAT }}
mutation ( run: |
$project: ID! gh api graphql -f query='
$item: ID! mutation (
$status_field: ID! $project: ID!
$status_value: String! $item: ID!
) { $status_field: ID!
set_status: updateProjectNextItemField(input: { $status_value: String!
projectId: $project ) {
itemId: $item set_status: updateProjectNextItemField(input: {
fieldId: $status_field projectId: $project
value: $status_value itemId: $item
}) { fieldId: $status_field
projectNextItem { value: $status_value
id }) {
} projectNextItem {
} id
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.INCOMING_OPTION_ID }} --silent }
}
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.INCOMING_OPTION_ID }} --silent

1
.prettierignore Normal file
View File

@@ -0,0 +1 @@
src/components/markdown/prism.ts

2
external/lang vendored

View File

@@ -133,6 +133,7 @@
"typescript": "^4.4.2", "typescript": "^4.4.2",
"ulid": "^2.3.0", "ulid": "^2.3.0",
"use-resize-observer": "^7.0.0", "use-resize-observer": "^7.0.0",
"vite-plugin-compression": "^0.3.6",
"vite-plugin-pwa": "^0.8.1", "vite-plugin-pwa": "^0.8.1",
"workbox-precaching": "^6.1.5" "workbox-precaching": "^6.1.5"
}, },

View File

@@ -5,7 +5,6 @@ import classNames from "classnames";
import { attachContextMenu } from "preact-context-menu"; import { attachContextMenu } from "preact-context-menu";
import { useContext, useState } from "preact/hooks"; import { useContext, useState } from "preact/hooks";
import { useIntermediate } from "../../../../context/intermediate/Intermediate";
import { AppContext } from "../../../../context/revoltjs/RevoltClient"; import { AppContext } from "../../../../context/revoltjs/RevoltClient";
import AttachmentActions from "./AttachmentActions"; import AttachmentActions from "./AttachmentActions";
@@ -39,7 +38,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
width={metadata.width} width={metadata.width}
height={metadata.height} height={metadata.height}
onContextMenu={attachContextMenu("Menu", { onContextMenu={attachContextMenu("Menu", {
attachment: attachment, attachment,
})} })}
className={classNames({ className={classNames({
[styles.margin]: hasContent, [styles.margin]: hasContent,

View File

@@ -98,6 +98,12 @@ export const ReplyBase = styled.div<{
transition: transform ease-in-out 0.1s; transition: transform ease-in-out 0.1s;
filter: brightness(1); filter: brightness(1);
> span > p {
display: flex;
align-items: center;
gap: 4px;
}
&:hover { &:hover {
filter: brightness(2); filter: brightness(2);
} }

View File

@@ -9,8 +9,6 @@ import MarkdownEmoji from "markdown-it-emoji/dist/markdown-it-emoji-bare";
import MarkdownSub from "markdown-it-sub"; import MarkdownSub from "markdown-it-sub";
// @ts-expect-error No typings. // @ts-expect-error No typings.
import MarkdownSup from "markdown-it-sup"; import MarkdownSup from "markdown-it-sup";
import Prism from "prismjs";
import "prismjs/themes/prism-tomorrow.css";
import { RE_MENTIONS } from "revolt.js"; import { RE_MENTIONS } from "revolt.js";
import styles from "./Markdown.module.scss"; import styles from "./Markdown.module.scss";
@@ -26,6 +24,7 @@ import { generateEmoji } from "../common/Emoji";
import { emojiDictionary } from "../../assets/emojis"; import { emojiDictionary } from "../../assets/emojis";
import { MarkdownProps } from "./Markdown"; import { MarkdownProps } from "./Markdown";
import Prism from "./prism";
// TODO: global.d.ts file for defining globals // TODO: global.d.ts file for defining globals
declare global { declare global {

View File

@@ -0,0 +1,104 @@
// This file handles importing Prism code highlighting library.
import Prism from "prismjs";
// Default: markup, html, xml, svg, mathml, ssml, atom,
// rss, css, clike, javascript, js
import "prismjs/components/prism-c.min.js";
import "prismjs/components/prism-cpp.min.js";
import "prismjs/components/prism-csharp";
import "prismjs/components/prism-bash.min.js";
import "prismjs/components/prism-json.min.js";
import "prismjs/components/prism-json5.min.js";
import "prismjs/components/prism-typescript";
import "prismjs/components/prism-rust";
import "prismjs/components/prism-markdown";
import "prismjs/components/prism-brainfuck";
import "prismjs/components/prism-diff";
import "prismjs/components/prism-ruby";
import "prismjs/components/prism-go";
import "prismjs/components/prism-ini";
import "prismjs/components/prism-toml";
import "prismjs/components/prism-java";
import "prismjs/components/prism-kotlin";
import "prismjs/components/prism-less";
import "prismjs/components/prism-scss";
import "prismjs/components/prism-sass";
import "prismjs/components/prism-lua";
import "prismjs/components/prism-makefile";
import "prismjs/components/prism-perl";
import "prismjs/components/prism-objectivec";
import "prismjs/components/prism-python";
import "prismjs/components/prism-r";
import "prismjs/components/prism-sql";
import "prismjs/components/prism-graphql";
import "prismjs/components/prism-shell-session";
import "prismjs/components/prism-java";
import "prismjs/components/prism-powershell";
import "prismjs/components/prism-swift";
import "prismjs/components/prism-yaml";
import "prismjs/components/prism-visual-basic";
import "prismjs/components/prism-asm6502";
import "prismjs/components/prism-nasm";
import "prismjs/components/prism-wasm";
import "prismjs/components/prism-llvm";
import "prismjs/components/prism-apacheconf";
import "prismjs/components/prism-dns-zone-file";
import "prismjs/components/prism-docker";
import "prismjs/components/prism-nginx";
import "prismjs/components/prism-coq";
import "prismjs/components/prism-elixir";
import "prismjs/components/prism-elm";
import "prismjs/components/prism-erlang";
import "prismjs/components/prism-fsharp";
import "prismjs/components/prism-haskell";
import "prismjs/components/prism-ocaml";
import "prismjs/components/prism-reason";
import "prismjs/components/prism-scala";
import "prismjs/components/prism-sml";
import "prismjs/components/prism-xquery";
import "prismjs/components/prism-glsl";
import "prismjs/components/prism-mel";
import "prismjs/components/prism-processing";
import "prismjs/components/prism-clojure";
import "prismjs/components/prism-lisp";
import "prismjs/components/prism-scheme";
import "prismjs/components/prism-asciidoc";
import "prismjs/components/prism-latex";
import "prismjs/components/prism-http";
import "prismjs/components/prism-protobuf";
import "prismjs/components/prism-fortran";
import "prismjs/components/prism-wolfram";
import "prismjs/components/prism-matlab";
import "prismjs/components/prism-mizar";
import "prismjs/components/prism-stan";
import "prismjs/components/prism-jsstacktrace";
import "prismjs/components/prism-javastacktrace";
import "prismjs/components/prism-actionscript";
import "prismjs/components/prism-applescript";
import "prismjs/components/prism-autohotkey";
import "prismjs/components/prism-autoit";
import "prismjs/components/prism-coffeescript";
import "prismjs/components/prism-dart";
import "prismjs/components/prism-gml";
import "prismjs/components/prism-livescript";
import "prismjs/components/prism-moonscript";
import "prismjs/components/prism-qml";
import "prismjs/components/prism-vim";
import "prismjs/components/prism-nim";
import "prismjs/components/prism-swift";
import "prismjs/components/prism-haml";
import "prismjs/components/prism-ada";
import "prismjs/components/prism-arduino";
import "prismjs/components/prism-basic";
import "prismjs/components/prism-crystal";
import "prismjs/components/prism-batch";
import "prismjs/components/prism-excel-formula";
import "prismjs/components/prism-ebnf";
import "prismjs/components/prism-haxe";
import "prismjs/components/prism-mongodb";
import "prismjs/themes/prism-tomorrow.css";
export default Prism;

View File

@@ -21,7 +21,7 @@ export default styled.button<Props>`
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 2px 16px; padding: 2px 16px;
font-size: 0.875rem; font-size: 0.8125rem;
font-family: inherit; font-family: inherit;
font-weight: 500; font-weight: 500;
flex-shrink: 0; flex-shrink: 0;

View File

@@ -61,29 +61,63 @@ const ModalBase = styled.div`
} }
`; `;
const ModalContainer = styled.div` const ModalContainer = styled.div<
{
[key in "userProfile"]?: boolean;
}
>`
overflow: hidden; overflow: hidden;
max-width: calc(100vw - 20px); padding: 12px;
width: 100%;
max-width: 440px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
animation-name: ${zoomIn}; animation-name: ${zoomIn};
animation-duration: 0.25s; animation-duration: 0.25s;
animation-timing-function: cubic-bezier(0.3, 0.3, 0.18, 1.1); animation-timing-function: cubic-bezier(0.3, 0.3, 0.18, 1.1);
${(props) =>
!props.userProfile &&
css`
max-width: max-content;
`}
`; `;
const ModalContent = styled.div< const ModalContent = styled.div<
{ [key in "attachment" | "noBackground" | "border" | "padding"]?: boolean } {
[key in
| "attachment"
| "noBackground"
| "border"
| "padding"
| "userProfile"]?: boolean;
}
>` >`
text-overflow: ellipsis; text-overflow: ellipsis;
border-radius: var(--border-radius); border-radius: var(--border-radius);
.title {
font-size: 14px;
text-decoration: underline;
}
h3 { h3 {
font-size: 14px;
text-transform: uppercase;
margin-top: 0; margin-top: 0;
} }
form { form {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px;
> div {
margin: 0;
color: var(--secondary-foreground);
font-size: 12px;
}
} }
${(props) => ${(props) =>
@@ -95,7 +129,7 @@ const ModalContent = styled.div<
${(props) => ${(props) =>
props.padding && props.padding &&
css` css`
padding: 1.5em; padding: 1rem;
`} `}
${(props) => ${(props) =>
@@ -117,7 +151,7 @@ const ModalActions = styled.div`
display: flex; display: flex;
flex-direction: row-reverse; flex-direction: row-reverse;
padding: 1em 1.5em; padding: 1rem;
background: var(--secondary-background); background: var(--secondary-background);
border-radius: 0 0 var(--border-radius) var(--border-radius); border-radius: 0 0 var(--border-radius) var(--border-radius);
`; `;
@@ -131,6 +165,7 @@ interface Props {
children?: Children; children?: Children;
title?: Children; title?: Children;
userProfile?: boolean;
disallowClosing?: boolean; disallowClosing?: boolean;
noBackground?: boolean; noBackground?: boolean;
dontModal?: boolean; dontModal?: boolean;
@@ -152,6 +187,7 @@ export default function Modal(props: Props) {
<ModalContent <ModalContent
attachment={!!props.actions} attachment={!!props.actions}
noBackground={props.noBackground} noBackground={props.noBackground}
userProfile={props.userProfile}
border={props.border} border={props.border}
padding={props.padding ?? !props.dontModal}> padding={props.padding ?? !props.dontModal}>
{props.title && <h3>{props.title}</h3>} {props.title && <h3>{props.title}</h3>}
@@ -209,7 +245,9 @@ export default function Modal(props: Props) {
<ModalBase <ModalBase
className={animateClose ? "closing" : undefined} className={animateClose ? "closing" : undefined}
onClick={(!props.disallowClosing && props.onClose) || undefined}> onClick={(!props.disallowClosing && props.onClose) || undefined}>
<ModalContainer onClick={(e) => (e.cancelBubble = true)}> <ModalContainer
onClick={(e) => (e.cancelBubble = true)}
userProfile={false}>
{content} {content}
{props.actions && ( {props.actions && (
<ModalActions> <ModalActions>

View File

@@ -1,4 +1,8 @@
import { ChevronRight, LinkExternal } from "@styled-icons/boxicons-regular"; import {
ChevronRight,
LinkExternal,
Pencil,
} from "@styled-icons/boxicons-regular";
import styled, { css } from "styled-components"; import styled, { css } from "styled-components";
import { Children } from "../../../types/Preact"; import { Children } from "../../../types/Preact";
@@ -11,7 +15,6 @@ interface BaseProps {
} }
const CategoryBase = styled.div<BaseProps>` const CategoryBase = styled.div<BaseProps>`
/*height: 54px;*/
padding: 9.8px 12px; padding: 9.8px 12px;
border-radius: var(--border-radius); border-radius: var(--border-radius);
margin-bottom: 10px; margin-bottom: 10px;
@@ -21,6 +24,7 @@ const CategoryBase = styled.div<BaseProps>`
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: row; flex-direction: row;
overflow: hidden;
> svg { > svg {
flex-shrink: 0; flex-shrink: 0;
@@ -142,7 +146,6 @@ export default function CategoryButton({
{icon} {icon}
<div class="content"> <div class="content">
<div className="title">{children}</div> <div className="title">{children}</div>
<div className="description">{description}</div> <div className="description">{description}</div>
</div> </div>
<div class="action"> <div class="action">

View File

@@ -123,29 +123,6 @@
} }
} }
.botStats {
background: var(--secondary-background);
border-radius: var(--border-radius);
padding: 10px;
font-size: 12px;
.stat {
display: flex;
align-items: center;
gap: 5px;
opacity: 0.5;
&:nth-child(1) {
opacity: 1;
> svg {
color: var(--accent);
}
}
}
}
> div { > div {
> span { > span {
font-size: 15px; font-size: 15px;
@@ -175,10 +152,6 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
background-color: var(--secondary-background); background-color: var(--secondary-background);
.info {
flex-grow: 1;
}
&:hover { &:hover {
background-color: var(--primary-background); background-color: var(--primary-background);
} }
@@ -194,19 +167,5 @@
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
font-size: 14px;
}
}
.botContainer {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 18px;
.owner {
text-transform: uppercase;
font-size: 10px;
font-weight: 600;
} }
} }

View File

@@ -1,17 +1,10 @@
import { import { ListUl } from "@styled-icons/boxicons-regular";
ListUl,
DotsVerticalRounded,
ChevronRight,
} from "@styled-icons/boxicons-regular";
import { import {
Envelope, Envelope,
Edit, Edit,
UserPlus, UserPlus,
Group, Group,
InfoCircle, InfoCircle,
BadgeCheck,
Cog,
TimeFive,
} from "@styled-icons/boxicons-solid"; } from "@styled-icons/boxicons-solid";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { Link, useHistory } from "react-router-dom"; import { Link, useHistory } from "react-router-dom";
@@ -164,6 +157,7 @@ export const UserProfile = observer(
backgroundImage: backgroundImage:
backgroundURL && backgroundURL &&
`linear-gradient( rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7) ), url('${backgroundURL}')`, `linear-gradient( rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7) ), url('${backgroundURL}')`,
paddingBottom: "1px",
}}> }}>
<div className={styles.profile}> <div className={styles.profile}>
<UserIcon <UserIcon
@@ -240,9 +234,6 @@ export const UserProfile = observer(
<UserPlus size={28} /> <UserPlus size={28} />
</IconButton> </IconButton>
)} )}
{/*<IconButton onClick={() => user.addFriend()}>
<DotsVerticalRounded size={26} />
</IconButton>*/}
</div> </div>
<div className={styles.tabs}> <div className={styles.tabs}>
<div <div
@@ -297,59 +288,31 @@ export const UserProfile = observer(
{user.bot ? ( {user.bot ? (
<> <>
<div className={styles.category}> <div className={styles.category}>
Bot information bot owner
</div> </div>
<div className={styles.botContainer}> <div
<div className={styles.botStats}> onClick={() =>
<div className={styles.stat}> user.bot &&
<BadgeCheck size="15" /> openScreen({
<b> id: "profile",
This bot has been user_id: user.bot.owner,
officially verified by })
Revolt }
</b> className={styles.entry}
</div> key={user.bot.owner}>
<div className={styles.stat}> <UserIcon
<Cog size="15" /> size={32}
Used in <b>456 servers</b> target={client.users.get(
</div> user.bot.owner,
<div className={styles.stat}> )}
<TimeFive size="14" /> />
Bot active since{" "} <span>
<b>Apr 15, 2019</b> <Username
</div> user={client.users.get(
</div>
<div
onClick={() =>
user.bot &&
openScreen({
id: "profile",
user_id: user.bot.owner,
})
}
className={styles.entry}
key={user.bot.owner}>
<UserIcon
size={32}
target={client.users.get(
user.bot.owner, user.bot.owner,
)} )}
/> />
<div className={styles.info}> </span>
<Username
user={client.users.get(
user.bot.owner,
)}
/>
<div
className={
styles.owner
}>
Bot owner
</div>
</div>
<ChevronRight size="24" />
</div>
</div> </div>
</> </>
) : undefined} ) : undefined}

View File

@@ -72,6 +72,7 @@
.small { .small {
display: flex; display: flex;
align-items: center;
font-size: 10px; font-size: 10px;
flex-direction: column; flex-direction: column;
color: var(--tertiary-foreground); color: var(--tertiary-foreground);

View File

@@ -20,33 +20,39 @@ type BehaviourType =
| { behaviour: "ask"; onChange: (file: File) => void } | { behaviour: "ask"; onChange: (file: File) => void }
| { behaviour: "upload"; onUpload: (id: string) => Promise<void> } | { behaviour: "upload"; onUpload: (id: string) => Promise<void> }
| { | {
behaviour: "multi"; behaviour: "multi";
onChange: (files: File[]) => void; onChange: (files: File[]) => void;
append?: (files: File[]) => void; append?: (files: File[]) => void;
} };
type StyleType = type StyleType =
| { | {
style: "icon" | "banner"; style: "icon" | "banner";
width?: number; width?: number;
height?: number; height?: number;
previewURL?: string; previewURL?: string;
defaultPreview?: string; defaultPreview?: string;
desaturateDefault?: boolean desaturateDefault?: boolean;
} }
| { | {
style: "attachment"; style: "attachment";
attached: boolean; attached: boolean;
uploading: boolean; uploading: boolean;
cancel: () => void; cancel: () => void;
size?: number; size?: number;
} };
type Props = BehaviourType & StyleType & { type Props = BehaviourType &
fileType: "backgrounds" | "icons" | "avatars" | "attachments" | "banners"; StyleType & {
maxFileSize: number; fileType:
remove: () => Promise<void>; | "backgrounds"
} | "icons"
| "avatars"
| "attachments"
| "banners";
maxFileSize: number;
remove: () => Promise<void>;
};
export async function uploadFile( export async function uploadFile(
autumnURL: string, autumnURL: string,
@@ -226,14 +232,19 @@ export function FileUploader(props: Props) {
})} })}
data-uploading={uploading}> data-uploading={uploading}>
<div <div
className={classNames(styles.image, props.desaturateDefault && previewURL == null && styles.desaturate)} className={classNames(
styles.image,
props.desaturateDefault &&
previewURL == null &&
styles.desaturate,
)}
style={{ style={{
backgroundImage: backgroundImage:
style === "icon" style === "icon"
? `url('${previewURL ?? defaultPreview}')` ? `url('${previewURL ?? defaultPreview}')`
: previewURL : previewURL
? `linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) ), url('${previewURL}')` ? `linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) ), url('${previewURL}')`
: "none", : "none",
width, width,
height, height,
}} }}

View File

@@ -63,22 +63,24 @@ function Notifier({ options, notifs }: Props) {
playSound("message"); playSound("message");
if (!showNotification) return; if (!showNotification) return;
const effectiveName = msg.masquerade?.name ?? msg.author?.username;
let title; let title;
switch (msg.channel?.channel_type) { switch (msg.channel?.channel_type) {
case "SavedMessages": case "SavedMessages":
return; return;
case "DirectMessage": case "DirectMessage":
title = `@${msg.author?.username}`; title = `@${effectiveName}`;
break; break;
case "Group": case "Group":
if (msg.author?._id === "00000000000000000000000000") { if (msg.author?._id === "00000000000000000000000000") {
title = msg.channel.name; title = msg.channel.name;
} else { } else {
title = `@${msg.author?.username} - ${msg.channel.name}`; title = `@${effectiveName} - ${msg.channel.name}`;
} }
break; break;
case "TextChannel": case "TextChannel":
title = `@${msg.author?.username} (#${msg.channel.name}, ${msg.channel.server?.name})`; title = `@${effectiveName} (#${msg.channel.name}, ${msg.channel.server?.name})`;
break; break;
default: default:
title = msg.channel?._id; title = msg.channel?._id;
@@ -100,7 +102,12 @@ function Notifier({ options, notifs }: Props) {
let body, icon; let body, icon;
if (typeof msg.content === "string") { if (typeof msg.content === "string") {
body = client.markdownToText(msg.content); body = client.markdownToText(msg.content);
icon = msg.author?.generateAvatarURL({ max_side: 256 });
if (msg.masquerade?.avatar) {
icon = client.proxyFile(msg.masquerade.avatar);
} else {
icon = msg.author?.generateAvatarURL({ max_side: 256 });
}
} else { } else {
const users = client.users; const users = client.users;
switch (msg.content.type) { switch (msg.content.type) {

View File

@@ -1,28 +1,53 @@
.home { .home {
height: 100%;
user-select: none; user-select: none;
position: relative;
h3 { .homeScreen {
margin: 1em 0;
font-size: 48px;
text-align: center;
img {
height: 36px;
}
}
.actions {
gap: 8px;
width: 236px;
margin: auto;
display: flex; display: flex;
width: fit-content;
align-items: stretch;
flex-direction: column; flex-direction: column;
justify-content: center;
align-items: center;
height: 95%;
padding: 12px;
h3 {
margin: 20px 0;
font-size: 48px;
text-align: center;
img {
height: 36px;
}
}
a { a {
width: 100%; font-size: 13px;
}
.actions {
//grid-template-columns: repeat(2, 300px);
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-column: span 2;
gap: 16px;
//margin: auto;
display: grid;
width: fit-content;
align-items: stretch;
flex-direction: column;
margin-bottom: 20px;
a {
width: 100%;
&:nth-child(4) {
margin-bottom: 20px;
}
div {
margin: 0;
}
}
} }
} }
} }

View File

@@ -1,10 +1,20 @@
import { Home as HomeIcon } from "@styled-icons/boxicons-solid"; import { Money } from "@styled-icons/boxicons-regular";
import {
Home as HomeIcon,
PlusCircle,
Compass,
Megaphone,
Group,
Cog,
RightArrowCircle,
} from "@styled-icons/boxicons-solid";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import styled, { css } from "styled-components"; import styled, { css } from "styled-components";
import styles from "./Home.module.scss"; import styles from "./Home.module.scss";
import "./snow.scss";
import { Text } from "preact-i18n"; import { Text } from "preact-i18n";
import { useContext, useState } from "preact/hooks"; import { useContext, useMemo, useState } from "preact/hooks";
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice"; import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
@@ -32,6 +42,19 @@ const IconConainer = styled.div`
`} `}
`; `;
const Overlay = styled.div`
display: grid;
height: 100%;
> * {
grid-area: 1 / 1;
}
.content {
z-index: 1;
}
`;
export default function Home() { export default function Home() {
const client = useContext(AppContext); const client = useContext(AppContext);
const [showChannels, setChannels] = useState( const [showChannels, setChannels] = useState(
@@ -59,68 +82,140 @@ export default function Home() {
} }
}; };
const snowflakes = useMemo(() => {
const flakes = [];
// Disable outside of December
if (new Date().getMonth() !== 11) return [];
for (let i = 0; i < 15; i++) {
flakes.push("❄️");
flakes.push("❄");
}
for (let i = 0; i < 2; i++) {
flakes.push("🎄");
flakes.push("☃️");
flakes.push("⛄");
}
return flakes;
}, []);
return ( return (
<div className={styles.home}> <div className={styles.home}>
<Header placement="primary"> <Overlay>
<IconConainer onClick={toggleChannelSidebar}> <div class="snowfall">
<HomeIcon size={24} /> {snowflakes.map((emoji, index) => (
</IconConainer> <div key={index} class="snowflake">
<Text id="app.navigation.tabs.home" /> {emoji}
</Header> </div>
<h3> ))}
<Text id="app.special.modals.onboarding.welcome" /> </div>
<br /> <div className="content">
<img src={wideSVG} /> <Header placement="primary">
</h3> <IconConainer onClick={toggleChannelSidebar}>
<div className={styles.actions}> <HomeIcon size={24} />
<Link to="/invite/Testers"> </IconConainer>
<CategoryButton <Text id="app.navigation.tabs.home" />
action="chevron" </Header>
icon={<Emoji emoji="😁" size={32} />}> <div className={styles.homeScreen}>
{client.servers.get("01F7ZSBSFHQ8TA81725KQCSDDP") ? ( <h3>
<Text id="app.home.goto-testers" /> <Text id="app.special.modals.onboarding.welcome" />
) : ( <br />
<Text id="app.home.join-testers" /> <img src={wideSVG} />
)} </h3>
</CategoryButton> <div className={styles.actions}>
</Link> <Link to="/settings">
<a <CategoryButton
href="https://insrt.uk/donate" action="chevron"
target="_blank" icon={<PlusCircle size={32} />}
rel="noreferrer"> description={
<CategoryButton "Invite all of your friends, some cool bots, and throw a big party."
action="external" }>
icon={<Emoji emoji="💷" size={32} />}> Create a group
<Text id="app.home.donate" /> </CategoryButton>
</CategoryButton> </Link>
</a> <a
<Link to="/settings/feedback"> href="https://revolt.social"
<CategoryButton target="_blank"
action="chevron" rel="noreferrer">
icon={<Emoji emoji="🎉" size={32} />}> <CategoryButton
<Text id="app.home.feedback" /> action="external"
</CategoryButton> icon={<Compass size={32} />}
</Link> description={
<a "Find a community based on your hobbies or interests."
href="https://revolt.social" }>
target="_blank" Join a community
rel="noreferrer"> </CategoryButton>
<CategoryButton </a>
action="external"
icon={<Emoji emoji="🧭" size={32} />}> {client.servers.get(
<Text id="app.home.social" /> "01F7ZSBSFHQ8TA81725KQCSDDP",
</CategoryButton> ) ? (
</a> <Link to="/server/01F7ZSBSFHQ8TA81725KQCSDDP">
<Tooltip content={<Text id="app.home.settings-tooltip" />}> <CategoryButton
<Link to="/settings"> action="chevron"
<CategoryButton icon={<RightArrowCircle size={32} />}
action="chevron" description={
icon={<Emoji emoji="🔧" size={32} />}> "You can report issues and discuss improvements with us directly here."
<Text id="app.home.settings" /> }>
</CategoryButton> <Text id="app.home.goto-testers" />
</Link> </CategoryButton>
</Tooltip> </Link>
</div> ) : (
<Link to="/invite/Testers">
<CategoryButton
action="chevron"
icon={<Group size={32} />}
description={
"You can report issues and discuss improvements with us directly here."
}>
<Text id="app.home.join-testers" />
</CategoryButton>
</Link>
)}
<Link to="/settings/feedback">
<CategoryButton
action="chevron"
icon={<Megaphone size={32} />}
description={
"Let us know how we can improve our app by giving us feedback."
}>
<Text id="app.home.feedback" />
</CategoryButton>
</Link>
<a
href="https://insrt.uk/donate"
target="_blank"
rel="noreferrer">
<CategoryButton
action="external"
icon={<Money size={32} />}>
<Text id="app.home.donate" />
</CategoryButton>
</a>
<Tooltip
content={
<Text id="app.home.settings-tooltip" />
}>
<Link to="/settings">
<CategoryButton
action="chevron"
icon={<Cog size={32} />}>
<Text id="app.home.settings" />
</CategoryButton>
</Link>
</Tooltip>
</div>
<Link to="/settings/appearance">
<a>Turn off homescreen effects</a>
</Link>
</div>
</div>
</Overlay>{" "}
</div> </div>
); );
} }

91
src/pages/home/snow.scss Normal file
View File

@@ -0,0 +1,91 @@
// Pure CSS Snowfall
// Released by Artimon under MIT license
//
// Source: https://github.com/Artimon/pure-css-snowfall
$count: 36;
$screenOffset: 0px;
$fallDuration: 12;
$windNoise: 30;
$windSpeed: 4;
$sizeNoise: 40;
$rotation: 360;
$imageSize: 20px;
$fontSize: 40px;
.snowfall {
z-index: 0;
display: block;
font-size: $fontSize;
overflow: hidden;
pointer-events: none;
.snowflake {
position: relative;
top: 0;
left: 0;
display: flex;
justify-content: center;
width: $screenOffset;
height: $screenOffset;
span {
align-self: center;
}
img {
align-self: center;
width: $imageSize;
}
}
@while ($count > 0) {
$left: random(100);
$deltaLeft: random(2 * $windNoise * 10) / 10 - $windNoise + $windSpeed;
$scale: 1 + (random(2 * $sizeNoise * 10) / 10 - $sizeNoise) / 100;
.snowflake:nth-child(#{$count}) {
animation: animation-snowflake-#{$count} linear infinite;
animation-duration: $fallDuration +
random($fallDuration * 10) /
10 +
s;
animation-delay: random(2 * $fallDuration * 10) /
10 -
(2 * $fallDuration) +
s;
}
@keyframes animation-snowflake-#{$count} {
0% {
left: percentage($left / 100);
top: calc(0% - #{$screenOffset});
transform: scale($scale)
rotate3d(
random(100) / 100,
random(100) / 100,
random(100) / 100,
0deg
);
}
100% {
left: percentage(($left + $deltaLeft) / 100);
top: calc(100% + #{$screenOffset});
transform: scale($scale)
rotate3d(
random(100) / 100,
random(100) / 100,
random(100) / 100,
(random($rotation) + $rotation) *
((random(2) - 1) * 2 - 1) + deg
);
}
}
$count: $count - 1;
}
}

View File

@@ -193,7 +193,9 @@
padding: 80px 32px; padding: 80px 32px;
width: 100%; width: 100%;
flex-direction: column; flex-direction: column;
height: fit-content;
// This prevents members, invites and ban list from being able to properly display.
// height: fit-content;
} }
details { details {
@@ -242,6 +244,10 @@
margin-top: 0; margin-top: 0;
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 400; font-weight: 400;
> a:hover {
text-decoration: underline;
}
} }
h6 { h6 {

View File

@@ -34,6 +34,7 @@ import {
OperationsContext, OperationsContext,
} from "../../context/revoltjs/RevoltClient"; } from "../../context/revoltjs/RevoltClient";
import UserIcon from "../../components/common/user/UserIcon";
import LineDivider from "../../components/ui/LineDivider"; import LineDivider from "../../components/ui/LineDivider";
import ButtonItem from "../../components/navigation/items/ButtonItem"; import ButtonItem from "../../components/navigation/items/ButtonItem";
@@ -54,7 +55,15 @@ import { Sessions } from "./panes/Sessions";
import { Sync } from "./panes/Sync"; import { Sync } from "./panes/Sync";
import { ThemeShop } from "./panes/ThemeShop"; import { ThemeShop } from "./panes/ThemeShop";
const IndexHeader = styled.div``; const IndexHeader = styled.div`
/*display: flex;*/
background: var(--secondary-background);
border-radius: var(--border-radius);
padding: 20px;
align-items: center;
gap: 10px;
display: none;
`;
export default function Settings() { export default function Settings() {
const history = useHistory(); const history = useHistory();
@@ -261,7 +270,12 @@ export default function Settings() {
</div> </div>
</> </>
} }
indexHeader={<IndexHeader>{/**/}</IndexHeader>} indexHeader={
<IndexHeader>
<UserIcon size={64} />
Username
</IndexHeader>
}
/> />
); );
} }

View File

@@ -1,4 +1,4 @@
import { At, Key, Block } from "@styled-icons/boxicons-regular"; import { At, Key, Block, ListOl } from "@styled-icons/boxicons-regular";
import { import {
Envelope, Envelope,
HelpCircle, HelpCircle,
@@ -165,6 +165,7 @@ export const Account = observer(() => {
</CategoryButton> </CategoryButton>
))} ))}
</div> </div>
<hr />
<h3> <h3>
<Text id="app.settings.pages.account.2fa.title" /> <Text id="app.settings.pages.account.2fa.title" />
</h3> </h3>
@@ -184,9 +185,17 @@ export const Account = observer(() => {
icon={<Lock size={24} color="var(--error)" />} icon={<Lock size={24} color="var(--error)" />}
description={"Set up 2FA on your account."} description={"Set up 2FA on your account."}
disabled disabled
action="chevron"> action={<Text id="general.unavailable" />}>
Set up Two-factor authentication Set up Two-factor authentication
</CategoryButton> </CategoryButton>
{/*<CategoryButton
icon={<ListOl size={24} />}
description={"View and download your 2FA backup codes."}
disabled
action="chevron">
View my backup codes
</CategoryButton>*/}
<hr />
<h3> <h3>
<Text id="app.settings.pages.account.manage.title" /> <Text id="app.settings.pages.account.manage.title" />
</h3> </h3>

View File

@@ -165,6 +165,20 @@ export function Component(props: Props) {
</h3> </h3>
<ColourSwatches value={theme.accent} onChange={setAccent} /> <ColourSwatches value={theme.accent} onChange={setAccent} />
{/* TOFIX: Chane this checkbox to turn off the seasonal home page animations*/}
<Checkbox
checked={props.settings.theme?.ligatures === true}
onChange={() =>
setTheme({
ligatures: !props.settings.theme?.ligatures,
})
}
description={
"Displays effects in the home tab during holiday seasons."
}>
Seasonal theme
</Checkbox>
{/*<h3> {/*<h3>
<Text id="app.settings.pages.appearance.message_display" /> <Text id="app.settings.pages.appearance.message_display" />
</h3> </h3>

View File

@@ -149,11 +149,21 @@
.badgePicker { .badgePicker {
display: flex; display: flex;
gap: 10px;
margin-bottom: 20px; margin-bottom: 20px;
//padding-bottom: 8px;
position: relative;
.container {
display: flex;
overflow-x: auto;
gap: 10px;
}
.check { .check {
cursor: pointer; cursor: pointer;
flex-shrink: 0;
height: 50px; height: 50px;
width: 50px; width: 50px;
background: var(--secondary-background); background: var(--secondary-background);
@@ -173,9 +183,41 @@
} }
} }
// TOFIX: need to merge overlay 1 and 2 later
.overlay {
position: absolute;
flex-shrink: 0;
width: 8px;
background: red;
height: 100%;
background: linear-gradient(
to right,
var(--primary-background),
transparent
);
}
.overlay2 {
position: absolute;
right: 0;
flex-shrink: 0;
width: 8px;
background: red;
height: 100%;
background: linear-gradient(
to left,
var(--primary-background),
transparent
);
}
.row { .row {
gap: 20px; gap: 20px;
display: flex; display: flex;
margin-bottom: 30px;
.pfp { .pfp {
display: flex; display: flex;

View File

@@ -74,10 +74,15 @@ export const Profile = observer(() => {
</div> </div>
{/*<h3>Badges</h3> {/*<h3>Badges</h3>
<div className={styles.badgePicker}> <div className={styles.badgePicker}>
<div className={styles.check}>a</div> <div className={styles.overlay} />
<div className={styles.check}>b</div> <div className={styles.container}>
<div className={styles.check}>c</div> <div className={styles.check}>a</div>
<div className={styles.check}>b</div>
<div className={styles.check}>c</div>
</div>
<div className={styles.overlay2} />
</div>*/} </div>*/}
<hr />
<div className={styles.row}> <div className={styles.row}>
<div className={styles.pfp}> <div className={styles.pfp}>
<h3> <h3>

View File

@@ -1,5 +1,5 @@
import { Chrome, Android, Apple, Windows } from "@styled-icons/boxicons-logos"; import { Chrome, Android, Apple, Windows } from "@styled-icons/boxicons-logos";
import { HelpCircle, Desktop } from "@styled-icons/boxicons-regular"; import { HelpCircle, Desktop, LogOut } from "@styled-icons/boxicons-regular";
import { import {
Safari, Safari,
Firefoxbrowser, Firefoxbrowser,
@@ -24,6 +24,7 @@ import { AppContext } from "../../../context/revoltjs/RevoltClient";
import Button from "../../../components/ui/Button"; import Button from "../../../components/ui/Button";
import Preloader from "../../../components/ui/Preloader"; import Preloader from "../../../components/ui/Preloader";
import Tip from "../../../components/ui/Tip"; import Tip from "../../../components/ui/Tip";
import CategoryButton from "../../../components/ui/fluent/CategoryButton";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
@@ -207,7 +208,7 @@ export function Sessions() {
</div> </div>
); );
})} })}
<Button {/*<Button
error error
onClick={async () => { onClick={async () => {
// ! FIXME: add to rAuth // ! FIXME: add to rAuth
@@ -230,7 +231,37 @@ export function Sessions() {
setSessions(sessions.filter((x) => x._id === deviceId)); setSessions(sessions.filter((x) => x._id === deviceId));
}}> }}>
<Text id="app.settings.pages.sessions.logout" /> <Text id="app.settings.pages.sessions.logout" />
</Button> </Button>*/}
<hr />
<CategoryButton
onClick={async () => {
// ! FIXME: add to rAuth
const del: string[] = [];
render.forEach((session) => {
if (deviceId !== session._id) {
del.push(session._id);
}
});
setDelete(del);
for (const id of del) {
await client.req(
"DELETE",
`/auth/session/${id}` as "/auth/session/id",
);
}
setSessions(sessions.filter((x) => x._id === deviceId));
}}
icon={<LogOut size={24} color={"var(--error)"} />}
action={"chevron"}
description={
"Logs you out of all sessions except this device."
}>
<Text id="app.settings.pages.sessions.logout" />
</CategoryButton>
<Tip> <Tip>
<span> <span>
<Text id="app.settings.tips.sessions.a" /> <Text id="app.settings.tips.sessions.a" />

View File

@@ -296,6 +296,7 @@ export function ThemeShop() {
<Tip warning hideSeparator> <Tip warning hideSeparator>
The Theme Shop is currently under construction. The Theme Shop is currently under construction.
</Tip> </Tip>
<hr />
{/* FIXME INTEGRATE WITH MOBX */} {/* FIXME INTEGRATE WITH MOBX */}
{/*<ActiveTheme> {/*<ActiveTheme>
<div class="active-indicator"> <div class="active-indicator">

View File

@@ -49,6 +49,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: row; flex-direction: row;
border-radius: var(--border-radius);
background: var(--secondary-background); background: var(--secondary-background);
span, span,
@@ -76,6 +77,9 @@
} }
} }
.invite {
}
.member { .member {
cursor: pointer; cursor: pointer;
@@ -95,12 +99,18 @@
.virtual { .virtual {
flex-grow: 1; flex-grow: 1;
> div > div > div {
display: flex;
flex-direction: column;
gap: 8px;
flex-grow: 1;
}
} }
} }
.roles { .roles {
gap: 12px; gap: 12px;
height: 100%; height: auto;
display: flex; display: flex;
.list { .list {

View File

@@ -2,6 +2,7 @@ import replace from "@rollup/plugin-replace";
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { resolve } from "path"; import { resolve } from "path";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import viteCompression from "vite-plugin-compression";
import { VitePWA } from "vite-plugin-pwa"; import { VitePWA } from "vite-plugin-pwa";
import preact from "@preact/preset-vite"; import preact from "@preact/preset-vite";
@@ -42,6 +43,10 @@ function getVersion() {
export default defineConfig({ export default defineConfig({
plugins: [ plugins: [
viteCompression({
verbose: true,
algorithm: "brotliCompress",
}),
preact(), preact(),
VitePWA({ VitePWA({
srcDir: "src", srcDir: "src",

View File

@@ -1877,7 +1877,7 @@ chalk@^2.0.0:
escape-string-regexp "^1.0.5" escape-string-regexp "^1.0.5"
supports-color "^5.3.0" supports-color "^5.3.0"
chalk@^4.0.0: chalk@^4.0.0, chalk@^4.1.2:
version "4.1.2" version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -4317,6 +4317,15 @@ value-equal@^1.0.1:
resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
vite-plugin-compression@^0.3.6:
version "0.3.6"
resolved "https://registry.yarnpkg.com/vite-plugin-compression/-/vite-plugin-compression-0.3.6.tgz#85e3ce5047ae6747bc3952177177a852fac901be"
integrity sha512-aSskQCJsP3VQ8PsnY+vO7UfD5qoFMOEuzg0PG2E9Zqyx+ARmc3wr9KCgOFraZOFW1Y4UAa5BR0SMTjoxHRMJoQ==
dependencies:
chalk "^4.1.2"
debug "^4.3.2"
fs-extra "^10.0.0"
vite-plugin-pwa@^0.8.1: vite-plugin-pwa@^0.8.1:
version "0.8.2" version "0.8.2"
resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-0.8.2.tgz#2789a157e2f71faf834d968945efc22eee9ad64a" resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-0.8.2.tgz#2789a157e2f71faf834d968945efc22eee9ad64a"