3 Commits

Author SHA1 Message Date
izzy
57e8c0e274 chore: sign post new app & fix logo 2026-06-23 09:55:47 +01:00
izzy
38f95897ca ci: brand assets
Signed-off-by: izzy <me@insrt.uk>
2026-06-23 09:06:08 +01:00
izzy
4cb8b370fe ci: build to registry
Signed-off-by: izzy <me@insrt.uk>
2026-06-23 08:51:37 +01:00
31 changed files with 412 additions and 492 deletions

1
.envrc
View File

@@ -1 +0,0 @@
use flake

66
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Bug report
description: File a bug report
title: "bug: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: what-happened
attributes:
label: What happened?
description: What did you expect to happen?
validations:
required: true
- type: dropdown
id: branch
attributes:
label: Branch
description: What branch of Revolt are you using?
options:
- Production (app.revolt.chat)
- Nightly (nightly.revolt.chat)
validations:
required: true
- type: textarea
id: commit-hash
attributes:
label: Commit hash
description: What is your commit hash? You can find this at the bottom of Settings, next to the branch name.
validations:
required: true
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Firefox
- Chrome
- Safari
- Microsoft Edge
- Other (please specify in the "What happened" form)
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. (To get this, press `CTRL`- or `CMD`-`SHIFT`-`I` and navigate to the "Console" tab.)
render: shell
- type: checkboxes
id: desktop
attributes:
label: Desktop
description: Is this bug specific to [the desktop client](https://github.com/revoltchat/desktop)? (If not, leave this unchecked.)
options:
- label: Yes, this bug is specific to Revolt Desktop and is *not* an issue with Revolt Desktop itself.
required: false
- type: checkboxes
id: pwa
attributes:
label: PWA
description: Is this bug specific to the PWA (i.e. "installing" the web app on iOS or Android)? (If not, leave this unchecked.)
options:
- label: Yes, this bug is specific to the PWA.
required: false

7
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
contact_links:
- name: Lounge Chat
url: https://rvlt.gg/Testers
about: Ask questions and discuss with others.
- name: Discussions
url: https://github.com/orgs/revoltchat/discussions
about: For larger feature requests and general question & answer.

24
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Feature request
description: Make a feature request
title: "feature request: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Before you start, a lot of bigger features may be better suited as [API issues](https://github.com/revoltchat/delta/issues/new) or [centralised discussions](https://github.com/revoltchat/revolt/discussions/new).
- type: textarea
id: your-idea
attributes:
label: What do you want to see?
description: Describe your idea in as much detail as possible - if applicable, screenshots/mockups are really useful.
validations:
required: true
- type: checkboxes
id: pwa
attributes:
label: PWA
description: Is this feature request specific to the PWA (i.e. "installing" the web app on iOS or Android)? (If not, leave this unchecked.)
options:
- label: Yes, this feature request is specific to the PWA.
required: false

7
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,7 @@
## Please make sure to check the following tasks before opening and submitting a PR
* [ ] I understand and have followed the [contribution guide](https://developers.revolt.chat/contrib.html)
* [ ] I have tested my changes locally and they are working as intended
* [ ] These changes do not have any notable side effects on other Revolt projects
* [ ] (optional) I have opened a pull request on [the translation repository](https://github.com/revoltchat/translations)
* [ ] I have included screenshots to demonstrate my changes

View File

@@ -1,55 +1,73 @@
name: Docker
on:
push:
branches:
- "handmade"
pull_request:
branches:
- "handmade"
release:
types:
- published
push:
branches:
- "master"
tags:
- "*"
paths-ignore:
- ".github/**"
- "!.github/workflows/docker.yml"
- "!.github/workflows/preview_*.yml"
- ".vscode/**"
- ".gitignore"
- ".gitlab-ci.yml"
- "LICENSE"
- "README"
pull_request:
branches:
- "master"
paths-ignore:
- ".github/**"
- "!.github/workflows/docker.yml"
- "!.github/workflows/preview_*.yml"
- ".vscode/**"
- ".gitignore"
- ".gitlab-ci.yml"
- "LICENSE"
- "README"
workflow_dispatch:
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
if: github.event_name != 'pull_request'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Resolve registry host
id: registry
run: echo "host=${GITHUB_SERVER_URL#*://}" >> "$GITHUB_OUTPUT"
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.registry.outputs.host }}/${{ github.repository_owner }}/handmade-revolt-web-client
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
images: revoltchat/client, ghcr.io/revoltchat/client
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
- name: Login to registry
uses: docker/login-action@v3
if: github.event_name == 'release'
- name: Login to DockerHub
uses: docker/login-action@v1
if: github.event_name != 'pull_request'
with:
registry: ${{ steps.registry.outputs.host }}
username: ${{ secrets.PACKAGE_PUBLISH_USERNAME }}
password: ${{ secrets.PACKAGE_PUBLISH_TOKEN }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to Github Container Registry
uses: docker/login-action@v3
if: github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and publish
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name == 'release' }}
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
labels: ${{ steps.meta.outputs.labels }}

44
.github/workflows/harbor.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Publish to Harbor
on:
push:
branches:
- "master"
workflow_dispatch:
jobs:
legacy-frontend:
name: Build and push to Harbor
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Harbor
uses: docker/login-action@v3
with:
registry: registry.stoatinternal.com
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
registry.stoatinternal.com/stoat/legacy-frontend:${{ github.sha }}
registry.stoatinternal.com/stoat/legacy-frontend:latest
build-args: |
REVOLT_PUBLIC_URL=https://api.stoat.chat/
REVOLT_SAAS=https://git.stoatinternal.com/brand/assets.git
REVOLT_SAAS_BRANCH=for-legacy-web
cache-from: type=gha
cache-to: type=gha,mode=max

54
.github/workflows/triage_issue.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: Add Issue to Board
on:
issues:
types: [opened]
jobs:
track_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
run: |
gh api graphql -f query='
query {
organization(login: "revoltchat"){
projectV2(number: 3) {
id
fields(first:20) {
nodes {
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}' > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV
- name: Add issue to project
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql -f query='
mutation($project:ID!, $issue:ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) {
item {
id
}
}
}' -f project=$PROJECT_ID -f issue=$ISSUE_ID --jq '.data.addProjectV2ItemById.item.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV

79
.github/workflows/triage_pr.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
name: Add PR to Board
on:
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"){
projectV2(number: 5) {
id
fields(first:20) {
nodes {
... on ProjectV2SingleSelectField {
id
name
options {
id
name
}
}
}
}
}
}
}' > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'INCOMING_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="🆕 Untriaged") |.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!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
item {
id
}
}
}' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"
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: updateProjectV2ItemFieldValue(input: {
projectId: $project
itemId: $item
fieldId: $status_field
value: {
singleSelectOptionId: $status_value
}
}) {
projectV2Item {
id
}
}
}' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.INCOMING_OPTION_ID }} --silent

2
.gitignore vendored
View File

@@ -15,5 +15,3 @@ public/assets_*
!public/assets_default
.vscode/chrome_data
.direnv

View File

@@ -8,11 +8,21 @@ COPY .env.build .env
RUN yarn install --frozen-lockfile
RUN yarn build:deps
# RUN yarn typecheck # lol no
ARG REVOLT_SAAS
ARG REVOLT_SAAS_BRANCH
ENV REVOLT_SAAS=$REVOLT_SAAS
ENV REVOLT_SAAS_BRANCH=$REVOLT_SAAS_BRANCH
RUN yarn build:highmem
RUN yarn workspaces focus --production --all
FROM node:24-alpine
WORKDIR /usr/src/app
ARG REVOLT_PUBLIC_URL=https://api.stoat.chat/
ENV REVOLT_PUBLIC_URL=$REVOLT_PUBLIC_URL
COPY docker/package.json docker/yarn.lock .
RUN yarn install --frozen-lockfile
COPY --from=builder --exclude=package.json --exclude=yarn.lock --exclude=.yarn* --exclude=.git --exclude=external --exclude=node_modules /usr/src/app .

View File

@@ -1,5 +1,8 @@
# Handmade Revolt
Fork of Revolt (now Stoat chat) maintained by the handmade cities community.
# Deprecation Notice
This project is deprecated, however it still may receive maintenance updates.
PRs for small fixes are more than welcome.
## Deploying a new release

64
flake.lock generated
View File

@@ -1,64 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1770169770,
"narHash": "sha256-awR8qIwJxJJiOmcEGgP2KUqYmHG4v/z8XpL9z8FnT1A=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "aa290c9891fa4ebe88f8889e59633d20cc06a5f2",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"systems": "systems"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View File

@@ -1,28 +0,0 @@
{
description = "Node+yarn dev shell flake";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
systems.url = "github:nix-systems/default";
flake-utils = {
url = "github:numtide/flake-utils";
inputs.systems.follows = "systems";
};
};
outputs =
{ nixpkgs, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
nodejs_24
yarn
];
};
}
);
}

View File

@@ -1,11 +1,11 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" background="#191919">
<head>
<meta charset="UTF-8" />
<!--App Title-->
<title>Revolt</title>
<meta name="apple-mobile-web-app-title" content="Revolt" />
<title>Stoat (Legacy)</title>
<meta name="apple-mobile-web-app-title" content="Stoat (Legacy)" />
<!--App Scaling-->
<meta

View File

@@ -16,11 +16,6 @@ import { IconButton } from "@revoltchat/ui";
import { emojiDictionary } from "../../../../assets/emojis";
import { useClient } from "../../../../controllers/client/ClientController";
import { modalController } from "../../../../controllers/modals/ModalController";
import { isTouchscreenDevice } from "../../../../lib/isTouchscreenDevice";
import Tooltip from "../../Tooltip";
import UserIcon from "../../user/UserIcon";
import { Username } from "../../user/UserShort";
import { RenderEmoji } from "../../../markdown/plugins/emoji";
import { HackAlertThisFileWillBeReplaced } from "../MessageBox";
@@ -90,38 +85,6 @@ const Reaction = styled.div<{ active: boolean }>`
`}
`;
/**
* Tooltip content for reaction users
*/
const TooltipUserList = styled.div`
display: flex;
flex-direction: column;
gap: 4px;
padding: 4px 0;
max-width: 200px;
`;
const TooltipUserRow = styled.div`
display: flex;
align-items: center;
gap: 6px;
font-size: 0.9em;
padding: 4px 6px;
margin: -4px -6px;
border-radius: var(--border-radius);
cursor: pointer;
&:hover {
background: var(--secondary-background);
}
`;
const TooltipMoreText = styled.div`
font-size: 0.85em;
color: var(--secondary-foreground);
padding-top: 2px;
`;
/**
* Render reactions on a message
*/
@@ -135,97 +98,16 @@ export const Reactions = observer(({ message }: Props) => {
const Entry = useCallback(
observer(({ id, user_ids }: { id: string; user_ids?: Set<string> }) => {
const active = user_ids?.has(client.user!._id) || false;
const userIds = user_ids ? Array.from(user_ids) : [];
const longPressTimer = useRef<number | null>(null);
const didLongPress = useRef(false);
const handleClick = () => {
if (didLongPress.current) {
didLongPress.current = false;
return;
}
active ? message.unreact(id) : message.react(id);
};
const openModal = () => {
modalController.push({
type: "reaction_users",
emoji: id,
userIds,
});
};
const handleTouchStart = (e: TouchEvent) => {
e.preventDefault();
e.stopPropagation();
didLongPress.current = false;
longPressTimer.current = window.setTimeout(() => {
didLongPress.current = true;
openModal();
}, 500);
};
const handleTouchEnd = (e: TouchEvent) => {
e.stopPropagation();
if (longPressTimer.current) {
clearTimeout(longPressTimer.current);
longPressTimer.current = null;
// Short tap - trigger manually since preventDefault blocks click
if (!didLongPress.current) {
active ? message.unreact(id) : message.react(id);
}
}
didLongPress.current = false;
};
const openUserProfile = (userId: string) => {
modalController.push({ type: "user_profile", user_id: userId });
};
// Build tooltip content showing up to 10 users
const tooltipContent = (
<TooltipUserList>
{userIds.slice(0, 10).map((userId) => {
const user = client.users.get(userId);
return (
<TooltipUserRow
key={userId}
onClick={() => openUserProfile(userId)}>
<UserIcon target={user} size={18} />
<Username user={user} />
</TooltipUserRow>
);
})}
{userIds.length > 10 && (
<TooltipMoreText>
and {userIds.length - 10} more...
</TooltipMoreText>
)}
</TooltipUserList>
);
const reactionElement = (
return (
<Reaction
active={active}
onClick={handleClick}
onTouchStart={isTouchscreenDevice ? handleTouchStart : undefined}
onTouchEnd={isTouchscreenDevice ? handleTouchEnd : undefined}
onTouchCancel={isTouchscreenDevice ? handleTouchEnd : undefined}>
onClick={() =>
active ? message.unreact(id) : message.react(id)
}>
<RenderEmoji match={id} /> {user_ids?.size || 0}
</Reaction>
);
// Desktop: show tooltip on hover
// Mobile: long-press opens modal, handled by touch events
if (!isTouchscreenDevice && userIds.length > 0) {
return (
<Tooltip content={tooltipContent} delay={300} interactive>
{reactionElement}
</Tooltip>
);
}
return reactionElement;
}),
[],
);

View File

@@ -119,7 +119,7 @@ export default function UserBadges({ badges, uid }: Props) {
}}
onClick={() => {
window.open(
"https://wiki.revolt.chat/notes/project/financial-support/",
"https://ko-fi.com/stoatchat",
"_blank",
);
}}

View File

@@ -121,7 +121,7 @@ export default function MemberList({
Offline users have temporarily been disabled for
larger servers - see{" "}
<a
href="https://github.com/revoltchat/backend/issues/178"
href="https://github.com/stoatchat/stoatchat/issues/178"
target="_blank"
rel="noreferrer">
issue #178

View File

@@ -78,6 +78,7 @@ export type Theme = Overrides & {
css?: string;
monospaceFont?: MonospaceFonts;
"min-opacity"?: number;
"logo-filter"?: string;
};
export type ComputedVariables = Theme & {
@@ -288,6 +289,7 @@ export const PRESETS: Record<string, Theme> = {
"status-busy": "#F84848",
"status-streaming": "#977EFF",
"status-invisible": "#A5A5A5",
"logo-filter": "unset",
},
dark: {
accent: "#FD6671",
@@ -316,6 +318,7 @@ export const PRESETS: Record<string, Theme> = {
"status-busy": "#F84848",
"status-streaming": "#977EFF",
"status-invisible": "#A5A5A5",
"logo-filter": "invert(1)",
},
};

View File

@@ -28,7 +28,6 @@ type Transition =
| "SUCCESS"
| "DISCONNECT"
| "RETRY"
| "RETRY_FAILED"
| "LOGOUT"
| "ONLINE"
| "OFFLINE";
@@ -41,7 +40,6 @@ export default class Session {
state: State = window.navigator.onLine ? "Ready" : "Offline";
user_id: string | null = null;
client: Client | null = null;
retryAttempts: number = 0;
/**
* Create a new Session
@@ -91,11 +89,9 @@ export default class Session {
* Called when the client signals it has disconnected
*/
private onDropped() {
if (this.state === "Connecting") {
this.emit({ action: "RETRY_FAILED" });
} else {
this.emit({ action: "DISCONNECT" });
}
this.emit({
action: "DISCONNECT",
});
}
/**
@@ -215,7 +211,6 @@ export default class Session {
// Ready successfully received
case "SUCCESS": {
this.assert("Connecting");
this.retryAttempts = 0;
this.state = "Online";
break;
}
@@ -244,18 +239,6 @@ export default class Session {
this.state = "Connecting";
break;
}
// Reconnect attempt failed, schedule another with backoff
case "RETRY_FAILED": {
this.assert("Connecting");
this.retryAttempts++;
const delay = Math.min(500 * Math.pow(2, this.retryAttempts), 16000);
setTimeout(() => {
if (this.state === "Connecting") {
this.client!.websocket.connect();
}
}, delay);
break;
}
// User instructed logout
case "LOGOUT": {
this.assert("Connecting", "Online", "Disconnected");

View File

@@ -32,8 +32,6 @@ import CreateRole from "./components/CreateRole";
import CreateServer from "./components/CreateServer";
import CustomStatus from "./components/CustomStatus";
import DeleteMessage from "./components/DeleteMessage";
import ReactMessage from "./components/ReactMessage";
import ReactionUsers from "./components/ReactionUsers";
import Error from "./components/Error";
import ImageViewer from "./components/ImageViewer";
import KickMember from "./components/KickMember";
@@ -277,8 +275,6 @@ export const modalController = new ModalControllerExtended({
create_bot: CreateBot,
custom_status: CustomStatus,
delete_message: DeleteMessage,
react_message: ReactMessage,
reaction_users: ReactionUsers,
error: Error,
image_viewer: ImageViewer,
kick_member: KickMember,

View File

@@ -1,46 +0,0 @@
import styled from "styled-components";
import { Modal } from "@revoltchat/ui";
import { ModalProps } from "../types"
import { Message } from "revolt.js";
import { emojiDictionary } from "../../../assets/emojis"
import { HackAlertThisFileWillBeReplaced } from "../../../components/common/messaging/MessageBox"
const PickerContainer = styled.div`
max-height: 420px;
max-width: 370px;
overflow: hidden;
> div {
position: unset;
}
`
export default function ReactMessage({
target: message,
onClose,
...props
}: ModalProps<"react_message">) {
return (
<Modal
{...props}
padding={false}
maxWidth="370px"
>
<PickerContainer>
<HackAlertThisFileWillBeReplaced
onSelect={(emoji) =>{
message.react(
emojiDictionary[
emoji as keyof typeof emojiDictionary
] ?? emoji,
);
onClose();
}}
onClose={onClose}
/>
</PickerContainer>
</Modal>
)
}

View File

@@ -1,92 +0,0 @@
import styled from "styled-components";
import { Modal } from "@revoltchat/ui";
import UserIcon from "../../../components/common/user/UserIcon";
import { Username } from "../../../components/common/user/UserShort";
import { RenderEmoji } from "../../../components/markdown/plugins/emoji";
import { useClient } from "../../client/ClientController";
import { modalController } from "../ModalController";
import { ModalProps } from "../types";
const List = styled.div`
max-width: 100%;
max-height: 360px;
overflow-y: auto;
`;
const UserRow = styled.div`
display: flex;
align-items: center;
gap: 8px;
padding: 8px;
cursor: pointer;
border-radius: var(--border-radius);
&:hover {
background: var(--secondary-background);
}
`;
const Header = styled.div`
display: flex;
align-items: center;
gap: 8px;
font-size: 1.1em;
img {
width: 1.5em;
height: 1.5em;
object-fit: contain;
}
`;
export default function ReactionUsers({
emoji,
userIds,
onClose,
...props
}: ModalProps<"reaction_users">) {
const client = useClient();
const openProfile = (userId: string) => {
onClose();
modalController.push({ type: "user_profile", user_id: userId });
};
// Modal must be nonDismissable, it conflicts with the message context menu otherwise.
return (
<Modal
{...props}
nonDismissable
title={
<Header>
<RenderEmoji match={emoji} />
<span>{userIds.length}</span>
</Header>
}
actions={[
{
onClick: () => {
onClose();
return true;
},
children: "Close",
},
]}>
<List>
{userIds.map((userId) => {
const user = client.users.get(userId);
return (
<UserRow
key={userId}
onClick={() => openProfile(userId)}>
<UserIcon target={user} size={32} />
<Username user={user} />
</UserRow>
);
})}
</List>
</Modal>
);
}

View File

@@ -153,15 +153,6 @@ export type Modal = {
type: "delete_message";
target: Message;
}
| {
type: "react_message",
target: Message;
}
| {
type: "reaction_users";
emoji: string;
userIds: string[];
}
| {
type: "kick_member";
member: Member;

View File

@@ -65,7 +65,6 @@ type Action =
| { action: "quote_message"; content: string }
| { action: "edit_message"; id: string }
| { action: "delete_message"; target: Message }
| { action: "react_message"; target: Message }
| { action: "open_file"; attachment: API.File }
| { action: "save_file"; attachment: API.File }
| { action: "copy_file_link"; attachment: API.File }
@@ -403,13 +402,6 @@ export default function ContextMenus() {
});
break;
case "react_message":
modalController.push({
type: "react_message",
target: data.target,
});
break;
case "leave_group":
case "close_dm":
case "delete_channel":
@@ -516,8 +508,6 @@ export default function ContextMenus() {
"Open in Admin Panel"
) : locale === "admin_system" ? (
"Open User in Admin Panel"
) : locale === "react_message" ? (
"React"
) : (
<Text
id={`app.context_menu.${
@@ -843,16 +833,6 @@ export default function ContextMenus() {
});
}
if (message.channel?.havePermission("React")) {
generateAction(
{
action: "react_message",
target: message,
},
"react_message",
);
}
if (message.author_id !== userId) {
generateAction(
{

View File

@@ -107,7 +107,10 @@ export default observer(() => {
<h3>
<Text id="app.special.modals.onboarding.welcome" />
<br />
<img src={wideSVG} />
<img
src={wideSVG}
style={{ filter: "var(--logo-filter)" }}
/>
</h3>
<div className={styles.actions}>
<a
@@ -164,18 +167,24 @@ export default observer(() => {
</Link>
)}
<Link to="/settings/feedback">
<a
href={
typeof window.native === "object"
? "https://stoat.chat/download"
: "https://stoat.chat/app"
}
target="_blank">
<CategoryButton
action="chevron"
icon={<Megaphone size={32} />}
description={
<Text id="app.home.feedback_desc" />
}>
<Text id="app.home.feedback" />
description="Revolt is now Stoat and has a brand new app.">
{typeof window.native === "object"
? "Download new app"
: "Switch to new app"}
</CategoryButton>
</Link>
</a>
<a
href="https://wiki.revolt.chat/notes/project/financial-support/"
href="https://ko-fi.com/stoatchat"
target="_blank"
rel="noreferrer">
<CategoryButton

View File

@@ -41,7 +41,9 @@ export default observer(() => {
href={action.href}
target="_blank"
rel="noreferrer">
<div className="button">{action.text}</div>{" "}
<div className="button">
{action.text}
</div>{" "}
</a>
) : null,
)}
@@ -59,7 +61,11 @@ export default observer(() => {
<div className={styles.nav}>
<a className={styles.logo}>
{!("native" in window) && (
<img src={wideSVG} draggable={false} />
<img
src={wideSVG}
style={{ filter: "var(--logo-filter)" }}
draggable={false}
/>
)}
</a>
<LocaleSelector />

View File

@@ -141,6 +141,10 @@
color: goldenrod !important;
}
.newApp {
color: green !important;
}
.logOut,
.deleteServer {
color: var(--error) !important;

View File

@@ -207,11 +207,6 @@ export default observer(() => {
icon: <Bot size={20} />,
title: <Text id="app.settings.pages.bots.title" />,
},
{
id: "feedback",
icon: <Megaphone size={20} />,
title: <Text id="app.settings.pages.feedback.title" />,
},
]}
children={
<Switch>
@@ -263,16 +258,23 @@ export default observer(() => {
category="pages"
custom={
<>
<ButtonItem
compact
onClick={() =>
modalController.push({ type: "changelog" })
}>
<ListUl size={20} />
<Text id="app.special.modals.changelogs.title" />
</ButtonItem>
{typeof window.native === "object" ? (
<a
className={styles.newApp}
href="https://stoat.chat/download"
target="_blank">
<ButtonItem compact>Download new app</ButtonItem>
</a>
) : (
<a
className={styles.newApp}
href="https://stoat.chat/app"
target="_blank">
<ButtonItem compact>Switch to new app</ButtonItem>
</a>
)}
<a
href="https://github.com/revoltchat"
href="https://github.com/stoatchat"
target="_blank"
rel="noreferrer">
<ButtonItem compact>
@@ -281,7 +283,7 @@ export default observer(() => {
</ButtonItem>
</a>
<a
href="https://wiki.revolt.chat/notes/project/financial-support/"
href="https://ko-fi.com/stoatchat"
target="_blank"
rel="noreferrer">
<ButtonItem className={styles.donate} compact>
@@ -309,7 +311,7 @@ export default observer(() => {
<a
href={
GIT_BRANCH !== "DETACHED"
? `https://github.com/revoltchat/revite/tree/${GIT_BRANCH}`
? `https://github.com/stoatchat/for-legacy-web/tree/${GIT_BRANCH}`
: undefined
}
target="_blank"

View File

@@ -33,9 +33,8 @@ export function Audio() {
const askOrGetPermission = async () => {
try {
const result = await navigator.mediaDevices.getUserMedia(
constraints,
);
const result =
await navigator.mediaDevices.getUserMedia(constraints);
setMediaStream(result);
} catch (err) {
@@ -96,28 +95,14 @@ export function Audio() {
<div className={styles.audio}>
<Tip palette="warning">
<span>
We are currently{" "}
Legacy voice is no longer supported,{" "}
<a
style={{ color: "inherit", fontWeight: "600" }}
href="https://github.com/revoltchat/frontend/issues/14"
target="_blank"
rel="noreferrer">
rebuilding the client
</a>{" "}
and{" "}
<a
style={{ color: "inherit", fontWeight: "600" }}
href="https://trello.com/c/Ay6KdiOV/1-voice-overhaul-and-video-calling"
target="_blank"
rel="noreferrer">
the voice server
</a>{" "}
from scratch.
<br />
<br />
The old voice should work in most cases, but it may
inexplicably not connect in some scenarios and / or
exhibit weird behaviour.
href="https://stoat.chat/app"
target="_blank">
use the new app
</a>
.
</span>
</Tip>

View File

@@ -1,7 +1,7 @@
/* eslint-disable */
// Strings needs to be explictly stated here as they can cause type issues elsewhere.
export const REPO_URL: string = "https://github.com/revoltchat/revite/commit";
export const REPO_URL: string = "https://github.com/stoatchat/for-legacy-web/commit";
export const GIT_REVISION: string = "__GIT_REVISION__";
export const GIT_BRANCH: string = "__GIT_BRANCH__";