mirror of
https://github.com/stoatchat/for-legacy-web.git
synced 2026-03-07 09:25:27 +00:00
Compare commits
12 Commits
ui/bot-pro
...
ui/setting
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bba9689e30 | ||
|
|
cc76e78db8 | ||
|
|
d2d7083542 | ||
|
|
73d99e4518 | ||
|
|
f14ef2b78f | ||
|
|
4719150368 | ||
|
|
3d73834bef | ||
|
|
1aff8ef516 | ||
|
|
b80a6a9c3e | ||
|
|
1780d06c97 | ||
|
|
c29efc155b | ||
|
|
71c0a782c1 |
6
.github/workflows/mirroring.yml
vendored
6
.github/workflows/mirroring.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Mirroring
|
||||
|
||||
on: [push, delete]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "production"
|
||||
|
||||
jobs:
|
||||
to_gitlab:
|
||||
|
||||
39
.github/workflows/preview_cleanup.yml
vendored
39
.github/workflows/preview_cleanup.yml
vendored
@@ -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
|
||||
52
.github/workflows/preview_pull_request.yml
vendored
52
.github/workflows/preview_pull_request.yml
vendored
@@ -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.
|
||||
128
.github/workflows/triage_pr.yml
vendored
128
.github/workflows/triage_pr.yml
vendored
@@ -1,72 +1,72 @@
|
||||
name: Add PR to Board
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, ready_for_review, review_requested]
|
||||
|
||||
jobs:
|
||||
track_pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get project data
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||
run: |
|
||||
gh api graphql -f query='
|
||||
query {
|
||||
organization(login: "revoltchat"){
|
||||
projectNext(number: 3) {
|
||||
id
|
||||
fields(first:20) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
settings
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' > project_data.json
|
||||
track_pr:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Get project data
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||
run: |
|
||||
gh api graphql -f query='
|
||||
query {
|
||||
organization(login: "revoltchat"){
|
||||
projectNext(number: 3) {
|
||||
id
|
||||
fields(first:20) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
settings
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}' > project_data.json
|
||||
|
||||
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 '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 '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 '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
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||
PR_ID: ${{ github.event.pull_request.node_id }}
|
||||
run: |
|
||||
item_id="$( gh api graphql -f query='
|
||||
mutation($project:ID!, $pr:ID!) {
|
||||
addProjectNextItem(input: {projectId: $project, contentId: $pr}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
|
||||
|
||||
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
|
||||
- name: Add PR to project
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||
PR_ID: ${{ github.event.pull_request.node_id }}
|
||||
run: |
|
||||
item_id="$( gh api graphql -f query='
|
||||
mutation($project:ID!, $pr:ID!) {
|
||||
addProjectNextItem(input: {projectId: $project, contentId: $pr}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
|
||||
|
||||
- name: Set fields
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||
run: |
|
||||
gh api graphql -f query='
|
||||
mutation (
|
||||
$project: ID!
|
||||
$item: ID!
|
||||
$status_field: ID!
|
||||
$status_value: String!
|
||||
) {
|
||||
set_status: updateProjectNextItemField(input: {
|
||||
projectId: $project
|
||||
itemId: $item
|
||||
fieldId: $status_field
|
||||
value: $status_value
|
||||
}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.INCOMING_OPTION_ID }} --silent
|
||||
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
|
||||
|
||||
- name: Set fields
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PAT }}
|
||||
run: |
|
||||
gh api graphql -f query='
|
||||
mutation (
|
||||
$project: ID!
|
||||
$item: ID!
|
||||
$status_field: ID!
|
||||
$status_value: String!
|
||||
) {
|
||||
set_status: updateProjectNextItemField(input: {
|
||||
projectId: $project
|
||||
itemId: $item
|
||||
fieldId: $status_field
|
||||
value: $status_value
|
||||
}) {
|
||||
projectNextItem {
|
||||
id
|
||||
}
|
||||
}
|
||||
}' -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
1
.prettierignore
Normal file
@@ -0,0 +1 @@
|
||||
src/components/markdown/prism.ts
|
||||
2
external/lang
vendored
2
external/lang
vendored
Submodule external/lang updated: 59fbe7c943...93ba149e7e
@@ -133,6 +133,7 @@
|
||||
"typescript": "^4.4.2",
|
||||
"ulid": "^2.3.0",
|
||||
"use-resize-observer": "^7.0.0",
|
||||
"vite-plugin-compression": "^0.3.6",
|
||||
"vite-plugin-pwa": "^0.8.1",
|
||||
"workbox-precaching": "^6.1.5"
|
||||
},
|
||||
|
||||
@@ -5,7 +5,6 @@ import classNames from "classnames";
|
||||
import { attachContextMenu } from "preact-context-menu";
|
||||
import { useContext, useState } from "preact/hooks";
|
||||
|
||||
import { useIntermediate } from "../../../../context/intermediate/Intermediate";
|
||||
import { AppContext } from "../../../../context/revoltjs/RevoltClient";
|
||||
|
||||
import AttachmentActions from "./AttachmentActions";
|
||||
@@ -39,7 +38,7 @@ export default function Attachment({ attachment, hasContent }: Props) {
|
||||
width={metadata.width}
|
||||
height={metadata.height}
|
||||
onContextMenu={attachContextMenu("Menu", {
|
||||
attachment: attachment,
|
||||
attachment,
|
||||
})}
|
||||
className={classNames({
|
||||
[styles.margin]: hasContent,
|
||||
|
||||
@@ -98,6 +98,12 @@ export const ReplyBase = styled.div<{
|
||||
transition: transform ease-in-out 0.1s;
|
||||
filter: brightness(1);
|
||||
|
||||
> span > p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
filter: brightness(2);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import MarkdownEmoji from "markdown-it-emoji/dist/markdown-it-emoji-bare";
|
||||
import MarkdownSub from "markdown-it-sub";
|
||||
// @ts-expect-error No typings.
|
||||
import MarkdownSup from "markdown-it-sup";
|
||||
import Prism from "prismjs";
|
||||
import "prismjs/themes/prism-tomorrow.css";
|
||||
import { RE_MENTIONS } from "revolt.js";
|
||||
|
||||
import styles from "./Markdown.module.scss";
|
||||
@@ -26,6 +24,7 @@ import { generateEmoji } from "../common/Emoji";
|
||||
|
||||
import { emojiDictionary } from "../../assets/emojis";
|
||||
import { MarkdownProps } from "./Markdown";
|
||||
import Prism from "./prism";
|
||||
|
||||
// TODO: global.d.ts file for defining globals
|
||||
declare global {
|
||||
|
||||
104
src/components/markdown/prism.ts
Normal file
104
src/components/markdown/prism.ts
Normal 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;
|
||||
@@ -21,7 +21,7 @@ export default styled.button<Props>`
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2px 16px;
|
||||
font-size: 0.875rem;
|
||||
font-size: 0.8125rem;
|
||||
font-family: inherit;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
|
||||
@@ -61,29 +61,63 @@ const ModalBase = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const ModalContainer = styled.div`
|
||||
const ModalContainer = styled.div<
|
||||
{
|
||||
[key in "userProfile"]?: boolean;
|
||||
}
|
||||
>`
|
||||
overflow: hidden;
|
||||
max-width: calc(100vw - 20px);
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
max-width: 440px;
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
animation-name: ${zoomIn};
|
||||
animation-duration: 0.25s;
|
||||
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<
|
||||
{ [key in "attachment" | "noBackground" | "border" | "padding"]?: boolean }
|
||||
{
|
||||
[key in
|
||||
| "attachment"
|
||||
| "noBackground"
|
||||
| "border"
|
||||
| "padding"
|
||||
| "userProfile"]?: boolean;
|
||||
}
|
||||
>`
|
||||
text-overflow: ellipsis;
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
> div {
|
||||
margin: 0;
|
||||
color: var(--secondary-foreground);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
${(props) =>
|
||||
@@ -95,7 +129,7 @@ const ModalContent = styled.div<
|
||||
${(props) =>
|
||||
props.padding &&
|
||||
css`
|
||||
padding: 1.5em;
|
||||
padding: 1rem;
|
||||
`}
|
||||
|
||||
${(props) =>
|
||||
@@ -117,7 +151,7 @@ const ModalActions = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
padding: 1em 1.5em;
|
||||
padding: 1rem;
|
||||
background: var(--secondary-background);
|
||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||
`;
|
||||
@@ -131,6 +165,7 @@ interface Props {
|
||||
children?: Children;
|
||||
title?: Children;
|
||||
|
||||
userProfile?: boolean;
|
||||
disallowClosing?: boolean;
|
||||
noBackground?: boolean;
|
||||
dontModal?: boolean;
|
||||
@@ -152,6 +187,7 @@ export default function Modal(props: Props) {
|
||||
<ModalContent
|
||||
attachment={!!props.actions}
|
||||
noBackground={props.noBackground}
|
||||
userProfile={props.userProfile}
|
||||
border={props.border}
|
||||
padding={props.padding ?? !props.dontModal}>
|
||||
{props.title && <h3>{props.title}</h3>}
|
||||
@@ -209,7 +245,9 @@ export default function Modal(props: Props) {
|
||||
<ModalBase
|
||||
className={animateClose ? "closing" : undefined}
|
||||
onClick={(!props.disallowClosing && props.onClose) || undefined}>
|
||||
<ModalContainer onClick={(e) => (e.cancelBubble = true)}>
|
||||
<ModalContainer
|
||||
onClick={(e) => (e.cancelBubble = true)}
|
||||
userProfile={false}>
|
||||
{content}
|
||||
{props.actions && (
|
||||
<ModalActions>
|
||||
|
||||
@@ -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 { Children } from "../../../types/Preact";
|
||||
@@ -11,7 +15,6 @@ interface BaseProps {
|
||||
}
|
||||
|
||||
const CategoryBase = styled.div<BaseProps>`
|
||||
/*height: 54px;*/
|
||||
padding: 9.8px 12px;
|
||||
border-radius: var(--border-radius);
|
||||
margin-bottom: 10px;
|
||||
@@ -21,6 +24,7 @@ const CategoryBase = styled.div<BaseProps>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
|
||||
> svg {
|
||||
flex-shrink: 0;
|
||||
@@ -142,7 +146,6 @@ export default function CategoryButton({
|
||||
{icon}
|
||||
<div class="content">
|
||||
<div className="title">{children}</div>
|
||||
|
||||
<div className="description">{description}</div>
|
||||
</div>
|
||||
<div class="action">
|
||||
|
||||
@@ -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 {
|
||||
> span {
|
||||
font-size: 15px;
|
||||
@@ -175,10 +152,6 @@
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--secondary-background);
|
||||
|
||||
.info {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--primary-background);
|
||||
}
|
||||
@@ -194,19 +167,5 @@
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import {
|
||||
ListUl,
|
||||
DotsVerticalRounded,
|
||||
ChevronRight,
|
||||
} from "@styled-icons/boxicons-regular";
|
||||
import { ListUl } from "@styled-icons/boxicons-regular";
|
||||
import {
|
||||
Envelope,
|
||||
Edit,
|
||||
UserPlus,
|
||||
Group,
|
||||
InfoCircle,
|
||||
BadgeCheck,
|
||||
Cog,
|
||||
TimeFive,
|
||||
} from "@styled-icons/boxicons-solid";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
@@ -164,6 +157,7 @@ export const UserProfile = observer(
|
||||
backgroundImage:
|
||||
backgroundURL &&
|
||||
`linear-gradient( rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7) ), url('${backgroundURL}')`,
|
||||
paddingBottom: "1px",
|
||||
}}>
|
||||
<div className={styles.profile}>
|
||||
<UserIcon
|
||||
@@ -240,9 +234,6 @@ export const UserProfile = observer(
|
||||
<UserPlus size={28} />
|
||||
</IconButton>
|
||||
)}
|
||||
{/*<IconButton onClick={() => user.addFriend()}>
|
||||
<DotsVerticalRounded size={26} />
|
||||
</IconButton>*/}
|
||||
</div>
|
||||
<div className={styles.tabs}>
|
||||
<div
|
||||
@@ -297,59 +288,31 @@ export const UserProfile = observer(
|
||||
{user.bot ? (
|
||||
<>
|
||||
<div className={styles.category}>
|
||||
Bot information
|
||||
bot owner
|
||||
</div>
|
||||
<div className={styles.botContainer}>
|
||||
<div className={styles.botStats}>
|
||||
<div className={styles.stat}>
|
||||
<BadgeCheck size="15" />
|
||||
<b>
|
||||
This bot has been
|
||||
officially verified by
|
||||
Revolt
|
||||
</b>
|
||||
</div>
|
||||
<div className={styles.stat}>
|
||||
<Cog size="15" />
|
||||
Used in <b>456 servers</b>
|
||||
</div>
|
||||
<div className={styles.stat}>
|
||||
<TimeFive size="14" />
|
||||
Bot active since{" "}
|
||||
<b>Apr 15, 2019</b>
|
||||
</div>
|
||||
</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(
|
||||
<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,
|
||||
)}
|
||||
/>
|
||||
<span>
|
||||
<Username
|
||||
user={client.users.get(
|
||||
user.bot.owner,
|
||||
)}
|
||||
/>
|
||||
<div className={styles.info}>
|
||||
<Username
|
||||
user={client.users.get(
|
||||
user.bot.owner,
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={
|
||||
styles.owner
|
||||
}>
|
||||
Bot owner
|
||||
</div>
|
||||
</div>
|
||||
<ChevronRight size="24" />
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : undefined}
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
|
||||
.small {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 10px;
|
||||
flex-direction: column;
|
||||
color: var(--tertiary-foreground);
|
||||
|
||||
@@ -20,33 +20,39 @@ type BehaviourType =
|
||||
| { behaviour: "ask"; onChange: (file: File) => void }
|
||||
| { behaviour: "upload"; onUpload: (id: string) => Promise<void> }
|
||||
| {
|
||||
behaviour: "multi";
|
||||
onChange: (files: File[]) => void;
|
||||
append?: (files: File[]) => void;
|
||||
}
|
||||
behaviour: "multi";
|
||||
onChange: (files: File[]) => void;
|
||||
append?: (files: File[]) => void;
|
||||
};
|
||||
|
||||
type StyleType =
|
||||
| {
|
||||
style: "icon" | "banner";
|
||||
width?: number;
|
||||
height?: number;
|
||||
previewURL?: string;
|
||||
defaultPreview?: string;
|
||||
desaturateDefault?: boolean
|
||||
}
|
||||
style: "icon" | "banner";
|
||||
width?: number;
|
||||
height?: number;
|
||||
previewURL?: string;
|
||||
defaultPreview?: string;
|
||||
desaturateDefault?: boolean;
|
||||
}
|
||||
| {
|
||||
style: "attachment";
|
||||
attached: boolean;
|
||||
uploading: boolean;
|
||||
cancel: () => void;
|
||||
size?: number;
|
||||
}
|
||||
style: "attachment";
|
||||
attached: boolean;
|
||||
uploading: boolean;
|
||||
cancel: () => void;
|
||||
size?: number;
|
||||
};
|
||||
|
||||
type Props = BehaviourType & StyleType & {
|
||||
fileType: "backgrounds" | "icons" | "avatars" | "attachments" | "banners";
|
||||
maxFileSize: number;
|
||||
remove: () => Promise<void>;
|
||||
}
|
||||
type Props = BehaviourType &
|
||||
StyleType & {
|
||||
fileType:
|
||||
| "backgrounds"
|
||||
| "icons"
|
||||
| "avatars"
|
||||
| "attachments"
|
||||
| "banners";
|
||||
maxFileSize: number;
|
||||
remove: () => Promise<void>;
|
||||
};
|
||||
|
||||
export async function uploadFile(
|
||||
autumnURL: string,
|
||||
@@ -226,14 +232,19 @@ export function FileUploader(props: Props) {
|
||||
})}
|
||||
data-uploading={uploading}>
|
||||
<div
|
||||
className={classNames(styles.image, props.desaturateDefault && previewURL == null && styles.desaturate)}
|
||||
className={classNames(
|
||||
styles.image,
|
||||
props.desaturateDefault &&
|
||||
previewURL == null &&
|
||||
styles.desaturate,
|
||||
)}
|
||||
style={{
|
||||
backgroundImage:
|
||||
style === "icon"
|
||||
? `url('${previewURL ?? defaultPreview}')`
|
||||
: previewURL
|
||||
? `linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) ), url('${previewURL}')`
|
||||
: "none",
|
||||
? `linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5) ), url('${previewURL}')`
|
||||
: "none",
|
||||
width,
|
||||
height,
|
||||
}}
|
||||
|
||||
@@ -63,22 +63,24 @@ function Notifier({ options, notifs }: Props) {
|
||||
playSound("message");
|
||||
if (!showNotification) return;
|
||||
|
||||
const effectiveName = msg.masquerade?.name ?? msg.author?.username;
|
||||
|
||||
let title;
|
||||
switch (msg.channel?.channel_type) {
|
||||
case "SavedMessages":
|
||||
return;
|
||||
case "DirectMessage":
|
||||
title = `@${msg.author?.username}`;
|
||||
title = `@${effectiveName}`;
|
||||
break;
|
||||
case "Group":
|
||||
if (msg.author?._id === "00000000000000000000000000") {
|
||||
title = msg.channel.name;
|
||||
} else {
|
||||
title = `@${msg.author?.username} - ${msg.channel.name}`;
|
||||
title = `@${effectiveName} - ${msg.channel.name}`;
|
||||
}
|
||||
break;
|
||||
case "TextChannel":
|
||||
title = `@${msg.author?.username} (#${msg.channel.name}, ${msg.channel.server?.name})`;
|
||||
title = `@${effectiveName} (#${msg.channel.name}, ${msg.channel.server?.name})`;
|
||||
break;
|
||||
default:
|
||||
title = msg.channel?._id;
|
||||
@@ -100,7 +102,12 @@ function Notifier({ options, notifs }: Props) {
|
||||
let body, icon;
|
||||
if (typeof msg.content === "string") {
|
||||
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 {
|
||||
const users = client.users;
|
||||
switch (msg.content.type) {
|
||||
|
||||
@@ -1,28 +1,53 @@
|
||||
.home {
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
|
||||
h3 {
|
||||
margin: 1em 0;
|
||||
font-size: 48px;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
gap: 8px;
|
||||
width: 236px;
|
||||
|
||||
margin: auto;
|
||||
.homeScreen {
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
align-items: stretch;
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 styled, { css } from "styled-components";
|
||||
|
||||
import styles from "./Home.module.scss";
|
||||
import "./snow.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
import { useContext, useState } from "preact/hooks";
|
||||
import { useContext, useMemo, useState } from "preact/hooks";
|
||||
|
||||
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() {
|
||||
const client = useContext(AppContext);
|
||||
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 (
|
||||
<div className={styles.home}>
|
||||
<Header placement="primary">
|
||||
<IconConainer onClick={toggleChannelSidebar}>
|
||||
<HomeIcon size={24} />
|
||||
</IconConainer>
|
||||
<Text id="app.navigation.tabs.home" />
|
||||
</Header>
|
||||
<h3>
|
||||
<Text id="app.special.modals.onboarding.welcome" />
|
||||
<br />
|
||||
<img src={wideSVG} />
|
||||
</h3>
|
||||
<div className={styles.actions}>
|
||||
<Link to="/invite/Testers">
|
||||
<CategoryButton
|
||||
action="chevron"
|
||||
icon={<Emoji emoji="😁" size={32} />}>
|
||||
{client.servers.get("01F7ZSBSFHQ8TA81725KQCSDDP") ? (
|
||||
<Text id="app.home.goto-testers" />
|
||||
) : (
|
||||
<Text id="app.home.join-testers" />
|
||||
)}
|
||||
</CategoryButton>
|
||||
</Link>
|
||||
<a
|
||||
href="https://insrt.uk/donate"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
<CategoryButton
|
||||
action="external"
|
||||
icon={<Emoji emoji="💷" size={32} />}>
|
||||
<Text id="app.home.donate" />
|
||||
</CategoryButton>
|
||||
</a>
|
||||
<Link to="/settings/feedback">
|
||||
<CategoryButton
|
||||
action="chevron"
|
||||
icon={<Emoji emoji="🎉" size={32} />}>
|
||||
<Text id="app.home.feedback" />
|
||||
</CategoryButton>
|
||||
</Link>
|
||||
<a
|
||||
href="https://revolt.social"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
<CategoryButton
|
||||
action="external"
|
||||
icon={<Emoji emoji="🧭" size={32} />}>
|
||||
<Text id="app.home.social" />
|
||||
</CategoryButton>
|
||||
</a>
|
||||
<Tooltip content={<Text id="app.home.settings-tooltip" />}>
|
||||
<Link to="/settings">
|
||||
<CategoryButton
|
||||
action="chevron"
|
||||
icon={<Emoji emoji="🔧" size={32} />}>
|
||||
<Text id="app.home.settings" />
|
||||
</CategoryButton>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Overlay>
|
||||
<div class="snowfall">
|
||||
{snowflakes.map((emoji, index) => (
|
||||
<div key={index} class="snowflake">
|
||||
{emoji}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="content">
|
||||
<Header placement="primary">
|
||||
<IconConainer onClick={toggleChannelSidebar}>
|
||||
<HomeIcon size={24} />
|
||||
</IconConainer>
|
||||
<Text id="app.navigation.tabs.home" />
|
||||
</Header>
|
||||
<div className={styles.homeScreen}>
|
||||
<h3>
|
||||
<Text id="app.special.modals.onboarding.welcome" />
|
||||
<br />
|
||||
<img src={wideSVG} />
|
||||
</h3>
|
||||
<div className={styles.actions}>
|
||||
<Link to="/settings">
|
||||
<CategoryButton
|
||||
action="chevron"
|
||||
icon={<PlusCircle size={32} />}
|
||||
description={
|
||||
"Invite all of your friends, some cool bots, and throw a big party."
|
||||
}>
|
||||
Create a group
|
||||
</CategoryButton>
|
||||
</Link>
|
||||
<a
|
||||
href="https://revolt.social"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
<CategoryButton
|
||||
action="external"
|
||||
icon={<Compass size={32} />}
|
||||
description={
|
||||
"Find a community based on your hobbies or interests."
|
||||
}>
|
||||
Join a community
|
||||
</CategoryButton>
|
||||
</a>
|
||||
|
||||
{client.servers.get(
|
||||
"01F7ZSBSFHQ8TA81725KQCSDDP",
|
||||
) ? (
|
||||
<Link to="/server/01F7ZSBSFHQ8TA81725KQCSDDP">
|
||||
<CategoryButton
|
||||
action="chevron"
|
||||
icon={<RightArrowCircle size={32} />}
|
||||
description={
|
||||
"You can report issues and discuss improvements with us directly here."
|
||||
}>
|
||||
<Text id="app.home.goto-testers" />
|
||||
</CategoryButton>
|
||||
</Link>
|
||||
) : (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
91
src/pages/home/snow.scss
Normal file
91
src/pages/home/snow.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,9 @@
|
||||
padding: 80px 32px;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
height: fit-content;
|
||||
|
||||
// This prevents members, invites and ban list from being able to properly display.
|
||||
// height: fit-content;
|
||||
}
|
||||
|
||||
details {
|
||||
@@ -242,6 +244,10 @@
|
||||
margin-top: 0;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
|
||||
> a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
h6 {
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
OperationsContext,
|
||||
} from "../../context/revoltjs/RevoltClient";
|
||||
|
||||
import UserIcon from "../../components/common/user/UserIcon";
|
||||
import LineDivider from "../../components/ui/LineDivider";
|
||||
|
||||
import ButtonItem from "../../components/navigation/items/ButtonItem";
|
||||
@@ -54,7 +55,15 @@ import { Sessions } from "./panes/Sessions";
|
||||
import { Sync } from "./panes/Sync";
|
||||
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() {
|
||||
const history = useHistory();
|
||||
@@ -261,7 +270,12 @@ export default function Settings() {
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
indexHeader={<IndexHeader>{/**/}</IndexHeader>}
|
||||
indexHeader={
|
||||
<IndexHeader>
|
||||
<UserIcon size={64} />
|
||||
Username
|
||||
</IndexHeader>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { At, Key, Block } from "@styled-icons/boxicons-regular";
|
||||
import { At, Key, Block, ListOl } from "@styled-icons/boxicons-regular";
|
||||
import {
|
||||
Envelope,
|
||||
HelpCircle,
|
||||
@@ -165,6 +165,7 @@ export const Account = observer(() => {
|
||||
</CategoryButton>
|
||||
))}
|
||||
</div>
|
||||
<hr />
|
||||
<h3>
|
||||
<Text id="app.settings.pages.account.2fa.title" />
|
||||
</h3>
|
||||
@@ -184,9 +185,17 @@ export const Account = observer(() => {
|
||||
icon={<Lock size={24} color="var(--error)" />}
|
||||
description={"Set up 2FA on your account."}
|
||||
disabled
|
||||
action="chevron">
|
||||
action={<Text id="general.unavailable" />}>
|
||||
Set up Two-factor authentication
|
||||
</CategoryButton>
|
||||
{/*<CategoryButton
|
||||
icon={<ListOl size={24} />}
|
||||
description={"View and download your 2FA backup codes."}
|
||||
disabled
|
||||
action="chevron">
|
||||
View my backup codes
|
||||
</CategoryButton>*/}
|
||||
<hr />
|
||||
<h3>
|
||||
<Text id="app.settings.pages.account.manage.title" />
|
||||
</h3>
|
||||
|
||||
@@ -165,6 +165,20 @@ export function Component(props: Props) {
|
||||
</h3>
|
||||
<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>
|
||||
<Text id="app.settings.pages.appearance.message_display" />
|
||||
</h3>
|
||||
|
||||
@@ -149,11 +149,21 @@
|
||||
|
||||
.badgePicker {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
//padding-bottom: 8px;
|
||||
position: relative;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
overflow-x: auto;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.check {
|
||||
cursor: pointer;
|
||||
|
||||
flex-shrink: 0;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
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 {
|
||||
gap: 20px;
|
||||
display: flex;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.pfp {
|
||||
display: flex;
|
||||
|
||||
@@ -74,10 +74,15 @@ export const Profile = observer(() => {
|
||||
</div>
|
||||
{/*<h3>Badges</h3>
|
||||
<div className={styles.badgePicker}>
|
||||
<div className={styles.check}>a</div>
|
||||
<div className={styles.check}>b</div>
|
||||
<div className={styles.check}>c</div>
|
||||
<div className={styles.overlay} />
|
||||
<div className={styles.container}>
|
||||
<div className={styles.check}>a</div>
|
||||
<div className={styles.check}>b</div>
|
||||
<div className={styles.check}>c</div>
|
||||
</div>
|
||||
<div className={styles.overlay2} />
|
||||
</div>*/}
|
||||
<hr />
|
||||
<div className={styles.row}>
|
||||
<div className={styles.pfp}>
|
||||
<h3>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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 {
|
||||
Safari,
|
||||
Firefoxbrowser,
|
||||
@@ -24,6 +24,7 @@ import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
||||
import Button from "../../../components/ui/Button";
|
||||
import Preloader from "../../../components/ui/Preloader";
|
||||
import Tip from "../../../components/ui/Tip";
|
||||
import CategoryButton from "../../../components/ui/fluent/CategoryButton";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
@@ -207,7 +208,7 @@ export function Sessions() {
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<Button
|
||||
{/*<Button
|
||||
error
|
||||
onClick={async () => {
|
||||
// ! FIXME: add to rAuth
|
||||
@@ -230,7 +231,37 @@ export function Sessions() {
|
||||
setSessions(sessions.filter((x) => x._id === deviceId));
|
||||
}}>
|
||||
<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>
|
||||
<span>
|
||||
<Text id="app.settings.tips.sessions.a" />
|
||||
|
||||
@@ -296,6 +296,7 @@ export function ThemeShop() {
|
||||
<Tip warning hideSeparator>
|
||||
The Theme Shop is currently under construction.
|
||||
</Tip>
|
||||
<hr />
|
||||
{/* FIXME INTEGRATE WITH MOBX */}
|
||||
{/*<ActiveTheme>
|
||||
<div class="active-indicator">
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--secondary-background);
|
||||
|
||||
span,
|
||||
@@ -76,6 +77,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
.invite {
|
||||
}
|
||||
|
||||
.member {
|
||||
cursor: pointer;
|
||||
|
||||
@@ -95,12 +99,18 @@
|
||||
|
||||
.virtual {
|
||||
flex-grow: 1;
|
||||
> div > div > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.roles {
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
height: auto;
|
||||
display: flex;
|
||||
|
||||
.list {
|
||||
|
||||
@@ -2,6 +2,7 @@ import replace from "@rollup/plugin-replace";
|
||||
import { readFileSync } from "fs";
|
||||
import { resolve } from "path";
|
||||
import { defineConfig } from "vite";
|
||||
import viteCompression from "vite-plugin-compression";
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
|
||||
import preact from "@preact/preset-vite";
|
||||
@@ -42,6 +43,10 @@ function getVersion() {
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
viteCompression({
|
||||
verbose: true,
|
||||
algorithm: "brotliCompress",
|
||||
}),
|
||||
preact(),
|
||||
VitePWA({
|
||||
srcDir: "src",
|
||||
|
||||
11
yarn.lock
11
yarn.lock
@@ -1877,7 +1877,7 @@ chalk@^2.0.0:
|
||||
escape-string-regexp "^1.0.5"
|
||||
supports-color "^5.3.0"
|
||||
|
||||
chalk@^4.0.0:
|
||||
chalk@^4.0.0, chalk@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||
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"
|
||||
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:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/vite-plugin-pwa/-/vite-plugin-pwa-0.8.2.tgz#2789a157e2f71faf834d968945efc22eee9ad64a"
|
||||
|
||||
Reference in New Issue
Block a user