mirror of
https://github.com/owncast/owncast.git
synced 2024-11-21 20:28:15 +03:00
Add support for changing user color in name modal. Closes #1805
This commit is contained in:
parent
9187a7a435
commit
68414445c2
22 changed files with 171 additions and 55 deletions
|
@ -11,6 +11,9 @@ const (
|
||||||
DataDirectory = "data"
|
DataDirectory = "data"
|
||||||
// EmojiDir is relative to the static directory.
|
// EmojiDir is relative to the static directory.
|
||||||
EmojiDir = "/img/emoji"
|
EmojiDir = "/img/emoji"
|
||||||
|
// MaxUserColor is the largest color value available to assign to users.
|
||||||
|
// They start at 0 and can be treated as IDs more than colors themselves.
|
||||||
|
MaxUserColor = 7
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/owncast/owncast/config"
|
||||||
"github.com/owncast/owncast/controllers"
|
"github.com/owncast/owncast/controllers"
|
||||||
"github.com/owncast/owncast/core/user"
|
"github.com/owncast/owncast/core/user"
|
||||||
"github.com/owncast/owncast/utils"
|
"github.com/owncast/owncast/utils"
|
||||||
|
@ -41,7 +42,7 @@ func CreateExternalAPIUser(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
color := utils.GenerateRandomDisplayColor()
|
color := utils.GenerateRandomDisplayColor(config.MaxUserColor)
|
||||||
|
|
||||||
if err := user.InsertExternalAPIUser(token, request.Name, color, request.Scopes); err != nil {
|
if err := user.InsertExternalAPIUser(token, request.Name, color, request.Scopes); err != nil {
|
||||||
controllers.InternalErrorHandler(w, err)
|
controllers.InternalErrorHandler(w, err)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/owncast/owncast/config"
|
||||||
"github.com/owncast/owncast/core/chat/events"
|
"github.com/owncast/owncast/core/chat/events"
|
||||||
"github.com/owncast/owncast/core/data"
|
"github.com/owncast/owncast/core/data"
|
||||||
"github.com/owncast/owncast/core/user"
|
"github.com/owncast/owncast/core/user"
|
||||||
|
@ -91,6 +92,25 @@ func (s *Server) userNameChanged(eventData chatClientEvent) {
|
||||||
eventData.client.sendConnectedClientInfo()
|
eventData.client.sendConnectedClientInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) userColorChanged(eventData chatClientEvent) {
|
||||||
|
var receivedEvent events.ColorChangeEvent
|
||||||
|
if err := json.Unmarshal(eventData.data, &receivedEvent); err != nil {
|
||||||
|
log.Errorln("error unmarshalling to ColorChangeEvent", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify this color is valid
|
||||||
|
if receivedEvent.NewColor > config.MaxUserColor {
|
||||||
|
log.Errorln("invalid color requested when changing user display color")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the new color
|
||||||
|
if err := user.ChangeUserColor(eventData.client.User.ID, receivedEvent.NewColor); err != nil {
|
||||||
|
log.Errorln("error changing user display color", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) userMessageSent(eventData chatClientEvent) {
|
func (s *Server) userMessageSent(eventData chatClientEvent) {
|
||||||
var event events.UserMessageEvent
|
var event events.UserMessageEvent
|
||||||
if err := json.Unmarshal(eventData.data, &event); err != nil {
|
if err := json.Unmarshal(eventData.data, &event); err != nil {
|
||||||
|
|
|
@ -10,6 +10,8 @@ const (
|
||||||
UserJoined EventType = "USER_JOINED"
|
UserJoined EventType = "USER_JOINED"
|
||||||
// UserNameChanged is the event sent when a chat username change takes place.
|
// UserNameChanged is the event sent when a chat username change takes place.
|
||||||
UserNameChanged EventType = "NAME_CHANGE"
|
UserNameChanged EventType = "NAME_CHANGE"
|
||||||
|
// UserColorChanged is the event sent when a chat user color change takes place.
|
||||||
|
UserColorChanged EventType = "COLOR_CHANGE"
|
||||||
// VisibiltyUpdate is the event sent when a chat message's visibility changes.
|
// VisibiltyUpdate is the event sent when a chat message's visibility changes.
|
||||||
VisibiltyUpdate EventType = "VISIBILITY-UPDATE"
|
VisibiltyUpdate EventType = "VISIBILITY-UPDATE"
|
||||||
// PING is a ping message.
|
// PING is a ping message.
|
||||||
|
|
|
@ -7,6 +7,13 @@ type NameChangeEvent struct {
|
||||||
NewName string `json:"newName"`
|
NewName string `json:"newName"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ColorChangeEvent is received when a user changes their chat display color.
|
||||||
|
type ColorChangeEvent struct {
|
||||||
|
Event
|
||||||
|
UserEvent
|
||||||
|
NewColor int `json:"newColor"`
|
||||||
|
}
|
||||||
|
|
||||||
// NameChangeBroadcast represents a user changing their chat display name.
|
// NameChangeBroadcast represents a user changing their chat display name.
|
||||||
type NameChangeBroadcast struct {
|
type NameChangeBroadcast struct {
|
||||||
Event
|
Event
|
||||||
|
|
|
@ -359,6 +359,8 @@ func (s *Server) eventReceived(event chatClientEvent) {
|
||||||
case events.UserNameChanged:
|
case events.UserNameChanged:
|
||||||
s.userNameChanged(event)
|
s.userNameChanged(event)
|
||||||
|
|
||||||
|
case events.UserColorChanged:
|
||||||
|
s.userColorChanged(event)
|
||||||
default:
|
default:
|
||||||
log.Debugln(eventType, "event not found:", typecheck)
|
log.Debugln(eventType, "event not found:", typecheck)
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,7 +291,7 @@ func migrateToSchema1(db *sql.DB) {
|
||||||
|
|
||||||
// Recreate them as users
|
// Recreate them as users
|
||||||
for _, token := range oldAccessTokens {
|
for _, token := range oldAccessTokens {
|
||||||
color := utils.GenerateRandomDisplayColor()
|
color := utils.GenerateRandomDisplayColor(config.MaxUserColor)
|
||||||
if err := insertAPIToken(db, token.accessToken, token.displayName, color, token.scopes); err != nil {
|
if err := insertAPIToken(db, token.accessToken, token.displayName, color, token.scopes); err != nil {
|
||||||
log.Errorln("Error migrating access token", err)
|
log.Errorln("Error migrating access token", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/owncast/owncast/config"
|
||||||
"github.com/owncast/owncast/core/data"
|
"github.com/owncast/owncast/core/data"
|
||||||
"github.com/owncast/owncast/db"
|
"github.com/owncast/owncast/db"
|
||||||
"github.com/owncast/owncast/utils"
|
"github.com/owncast/owncast/utils"
|
||||||
|
@ -70,7 +71,7 @@ func CreateAnonymousUser(displayName string) (*User, string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayColor := utils.GenerateRandomDisplayColor()
|
displayColor := utils.GenerateRandomDisplayColor(config.MaxUserColor)
|
||||||
|
|
||||||
user := &User{
|
user := &User{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
@ -125,6 +126,21 @@ func ChangeUsername(userID string, username string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChangeUserColor will change the user associated to userID from one display name to another.
|
||||||
|
func ChangeUserColor(userID string, color int) error {
|
||||||
|
_datastore.DbLock.Lock()
|
||||||
|
defer _datastore.DbLock.Unlock()
|
||||||
|
|
||||||
|
if err := _datastore.GetQueries().ChangeDisplayColor(context.Background(), db.ChangeDisplayColorParams{
|
||||||
|
DisplayColor: int32(color),
|
||||||
|
ID: userID,
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrap(err, "unable to change display color")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func addAccessTokenForUser(accessToken, userID string) error {
|
func addAccessTokenForUser(accessToken, userID string) error {
|
||||||
return _datastore.GetQueries().AddAccessTokenForUser(context.Background(), db.AddAccessTokenForUserParams{
|
return _datastore.GetQueries().AddAccessTokenForUser(context.Background(), db.AddAccessTokenForUserParams{
|
||||||
Token: accessToken,
|
Token: accessToken,
|
||||||
|
|
2
db/db.go
2
db/db.go
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.14.0
|
// sqlc v1.15.0
|
||||||
|
|
||||||
package db
|
package db
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.14.0
|
// sqlc v1.15.0
|
||||||
|
|
||||||
package db
|
package db
|
||||||
|
|
||||||
|
|
|
@ -105,3 +105,6 @@ SELECT count(*) FROM users WHERE display_name = $1 AND authenticated_at is not n
|
||||||
|
|
||||||
-- name: ChangeDisplayName :exec
|
-- name: ChangeDisplayName :exec
|
||||||
UPDATE users SET display_name = $1, previous_names = previous_names || $2, namechanged_at = $3 WHERE id = $4;
|
UPDATE users SET display_name = $1, previous_names = previous_names || $2, namechanged_at = $3 WHERE id = $4;
|
||||||
|
|
||||||
|
-- name: ChangeDisplayColor :exec
|
||||||
|
UPDATE users SET display_color = $1 WHERE id = $2;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.14.0
|
// sqlc v1.15.0
|
||||||
// source: query.sql
|
// source: query.sql
|
||||||
|
|
||||||
package db
|
package db
|
||||||
|
@ -153,6 +153,20 @@ func (q *Queries) BanIPAddress(ctx context.Context, arg BanIPAddressParams) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changeDisplayColor = `-- name: ChangeDisplayColor :exec
|
||||||
|
UPDATE users SET display_color = $1 WHERE id = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type ChangeDisplayColorParams struct {
|
||||||
|
DisplayColor int32
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) ChangeDisplayColor(ctx context.Context, arg ChangeDisplayColorParams) error {
|
||||||
|
_, err := q.db.ExecContext(ctx, changeDisplayColor, arg.DisplayColor, arg.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const changeDisplayName = `-- name: ChangeDisplayName :exec
|
const changeDisplayName = `-- name: ChangeDisplayName :exec
|
||||||
UPDATE users SET display_name = $1, previous_names = previous_names || $2, namechanged_at = $3 WHERE id = $4
|
UPDATE users SET display_name = $1, previous_names = previous_names || $2, namechanged_at = $3 WHERE id = $4
|
||||||
`
|
`
|
||||||
|
|
|
@ -324,10 +324,10 @@ func StringMapKeys(stringMap map[string]interface{}) []string {
|
||||||
// GenerateRandomDisplayColor will return a random number that is used for
|
// GenerateRandomDisplayColor will return a random number that is used for
|
||||||
// referencing a color value client-side. These colors are seen as
|
// referencing a color value client-side. These colors are seen as
|
||||||
// --theme-user-colors-n.
|
// --theme-user-colors-n.
|
||||||
func GenerateRandomDisplayColor() int {
|
func GenerateRandomDisplayColor(maxColor int) int {
|
||||||
rangeLower := 1
|
rangeLower := 0
|
||||||
rangeUpper := 8
|
rangeUpper := maxColor
|
||||||
return rangeLower + rand.Intn(rangeUpper-rangeLower+1) //nolint
|
return rangeLower + rand.Intn(rangeUpper-rangeLower+1) //nolint:gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHostnameFromURL will return the hostname component from a URL string.
|
// GetHostnameFromURL will return the hostname component from a URL string.
|
||||||
|
|
|
@ -1,16 +1,34 @@
|
||||||
import { useState } from 'react';
|
import React, { CSSProperties, useState } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Input, Button } from 'antd';
|
import { Input, Button, Select } from 'antd';
|
||||||
import { MessageType } from '../../interfaces/socket-events';
|
import { MessageType } from '../../interfaces/socket-events';
|
||||||
import WebsocketService from '../../services/websocket-service';
|
import WebsocketService from '../../services/websocket-service';
|
||||||
import { websocketServiceAtom, chatDisplayNameAtom } from '../stores/ClientConfigStore';
|
import {
|
||||||
|
websocketServiceAtom,
|
||||||
|
chatDisplayNameAtom,
|
||||||
|
chatDisplayColorAtom,
|
||||||
|
} from '../stores/ClientConfigStore';
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
|
function UserColor(props: { color: number }): React.ReactElement {
|
||||||
|
const { color } = props;
|
||||||
|
const style: CSSProperties = {
|
||||||
|
textAlign: 'center',
|
||||||
|
backgroundColor: `var(--theme-user-colors-${color})`,
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
};
|
||||||
|
return <div style={style} />;
|
||||||
|
}
|
||||||
|
|
||||||
export default function NameChangeModal(props: Props) {
|
export default function NameChangeModal(props: Props) {
|
||||||
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
|
const websocketService = useRecoilValue<WebsocketService>(websocketServiceAtom);
|
||||||
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom);
|
const chatDisplayName = useRecoilValue<string>(chatDisplayNameAtom);
|
||||||
|
const chatDisplayColor = useRecoilValue<number>(chatDisplayColorAtom);
|
||||||
const [newName, setNewName] = useState<any>(chatDisplayName);
|
const [newName, setNewName] = useState<any>(chatDisplayName);
|
||||||
|
|
||||||
const handleNameChange = () => {
|
const handleNameChange = () => {
|
||||||
|
@ -24,6 +42,17 @@ export default function NameChangeModal(props: Props) {
|
||||||
const saveEnabled =
|
const saveEnabled =
|
||||||
newName !== chatDisplayName && newName !== '' && websocketService?.isConnected();
|
newName !== chatDisplayName && newName !== '' && websocketService?.isConnected();
|
||||||
|
|
||||||
|
const handleColorChange = (color: string) => {
|
||||||
|
const colorChange = {
|
||||||
|
type: MessageType.COLOR_CHANGE,
|
||||||
|
newColor: Number(color),
|
||||||
|
};
|
||||||
|
websocketService.send(colorChange);
|
||||||
|
};
|
||||||
|
|
||||||
|
const maxColor = 8; // 0...n
|
||||||
|
const colorOptions = [...Array(maxColor)].map((e, i) => i);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Your chat display name is what people see when you send chat messages. Other information can
|
Your chat display name is what people see when you send chat messages. Other information can
|
||||||
|
@ -32,13 +61,28 @@ export default function NameChangeModal(props: Props) {
|
||||||
value={newName}
|
value={newName}
|
||||||
onChange={e => setNewName(e.target.value)}
|
onChange={e => setNewName(e.target.value)}
|
||||||
placeholder="Your chat display name"
|
placeholder="Your chat display name"
|
||||||
maxLength={10}
|
maxLength={30}
|
||||||
showCount
|
showCount
|
||||||
defaultValue={chatDisplayName}
|
defaultValue={chatDisplayName}
|
||||||
/>
|
/>
|
||||||
<Button disabled={!saveEnabled} onClick={handleNameChange}>
|
<Button disabled={!saveEnabled} onClick={handleNameChange}>
|
||||||
Change name
|
Change name
|
||||||
</Button>
|
</Button>
|
||||||
|
<div>
|
||||||
|
Your Color
|
||||||
|
<Select
|
||||||
|
style={{ width: 120 }}
|
||||||
|
onChange={handleColorChange}
|
||||||
|
defaultValue={chatDisplayColor.toString()}
|
||||||
|
getPopupContainer={triggerNode => triggerNode.parentElement}
|
||||||
|
>
|
||||||
|
{colorOptions.map(e => (
|
||||||
|
<Option key={e.toString()} title={e}>
|
||||||
|
<UserColor color={e} />
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,11 @@ export const chatDisplayNameAtom = atom<string>({
|
||||||
default: null,
|
default: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const chatDisplayColorAtom = atom<number>({
|
||||||
|
key: 'chatDisplayColor',
|
||||||
|
default: null,
|
||||||
|
});
|
||||||
|
|
||||||
export const chatUserIdAtom = atom<string>({
|
export const chatUserIdAtom = atom<string>({
|
||||||
key: 'chatUserIdAtom',
|
key: 'chatUserIdAtom',
|
||||||
default: null,
|
default: null,
|
||||||
|
@ -149,6 +154,7 @@ export function ClientConfigStore() {
|
||||||
const [appState, appStateSend, appStateService] = useMachine(appStateModel);
|
const [appState, appStateSend, appStateService] = useMachine(appStateModel);
|
||||||
|
|
||||||
const setChatDisplayName = useSetRecoilState<string>(chatDisplayNameAtom);
|
const setChatDisplayName = useSetRecoilState<string>(chatDisplayNameAtom);
|
||||||
|
const setChatDisplayColor = useSetRecoilState<Number>(chatDisplayColorAtom);
|
||||||
const setChatUserId = useSetRecoilState<string>(chatUserIdAtom);
|
const setChatUserId = useSetRecoilState<string>(chatUserIdAtom);
|
||||||
const setIsChatModerator = useSetRecoilState<boolean>(isChatModeratorAtom);
|
const setIsChatModerator = useSetRecoilState<boolean>(isChatModeratorAtom);
|
||||||
const setClientConfig = useSetRecoilState<ClientConfig>(clientConfigStateAtom);
|
const setClientConfig = useSetRecoilState<ClientConfig>(clientConfigStateAtom);
|
||||||
|
@ -225,7 +231,7 @@ export function ClientConfigStore() {
|
||||||
sendEvent(AppStateEvent.NeedsRegister);
|
sendEvent(AppStateEvent.NeedsRegister);
|
||||||
const response = await ChatService.registerUser(optionalDisplayName);
|
const response = await ChatService.registerUser(optionalDisplayName);
|
||||||
console.log(`ChatService -> registerUser() response: \n${response}`);
|
console.log(`ChatService -> registerUser() response: \n${response}`);
|
||||||
const { accessToken: newAccessToken, displayName: newDisplayName } = response;
|
const { accessToken: newAccessToken, displayName: newDisplayName, displayColor } = response;
|
||||||
if (!newAccessToken) {
|
if (!newAccessToken) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -234,6 +240,7 @@ export function ClientConfigStore() {
|
||||||
setAccessToken(newAccessToken);
|
setAccessToken(newAccessToken);
|
||||||
setLocalStorage(ACCESS_TOKEN_KEY, newAccessToken);
|
setLocalStorage(ACCESS_TOKEN_KEY, newAccessToken);
|
||||||
setChatDisplayName(newDisplayName);
|
setChatDisplayName(newDisplayName);
|
||||||
|
setChatDisplayColor(displayColor);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
sendEvent(AppStateEvent.Fail);
|
sendEvent(AppStateEvent.Fail);
|
||||||
console.error(`ChatService -> registerUser() ERROR: \n${e}`);
|
console.error(`ChatService -> registerUser() ERROR: \n${e}`);
|
||||||
|
@ -255,6 +262,7 @@ export function ClientConfigStore() {
|
||||||
handleConnectedClientInfoMessage(
|
handleConnectedClientInfoMessage(
|
||||||
message as ConnectedClientInfoEvent,
|
message as ConnectedClientInfoEvent,
|
||||||
setChatDisplayName,
|
setChatDisplayName,
|
||||||
|
setChatDisplayColor,
|
||||||
setChatUserId,
|
setChatUserId,
|
||||||
setIsChatModerator,
|
setIsChatModerator,
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,12 +3,14 @@ import { ConnectedClientInfoEvent } from '../../../interfaces/socket-events';
|
||||||
export default function handleConnectedClientInfoMessage(
|
export default function handleConnectedClientInfoMessage(
|
||||||
message: ConnectedClientInfoEvent,
|
message: ConnectedClientInfoEvent,
|
||||||
setChatDisplayName: (string) => void,
|
setChatDisplayName: (string) => void,
|
||||||
|
setChatDisplayColor: (number) => void,
|
||||||
setChatUserId: (number) => void,
|
setChatUserId: (number) => void,
|
||||||
setIsChatModerator: (boolean) => void,
|
setIsChatModerator: (boolean) => void,
|
||||||
) {
|
) {
|
||||||
const { user } = message;
|
const { user } = message;
|
||||||
const { id, displayName, scopes } = user;
|
const { id, displayName, displayColor, scopes } = user;
|
||||||
setChatDisplayName(displayName);
|
setChatDisplayName(displayName);
|
||||||
|
setChatDisplayColor(displayColor);
|
||||||
setChatUserId(id);
|
setChatUserId(id);
|
||||||
setIsChatModerator(scopes?.includes('moderator'));
|
setIsChatModerator(scopes?.includes('moderator'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ export enum MessageType {
|
||||||
CHAT = 'CHAT',
|
CHAT = 'CHAT',
|
||||||
PING = 'PING',
|
PING = 'PING',
|
||||||
NAME_CHANGE = 'NAME_CHANGE',
|
NAME_CHANGE = 'NAME_CHANGE',
|
||||||
|
COLOR_CHANGE = 'COLOR_CHANGE',
|
||||||
PONG = 'PONG',
|
PONG = 'PONG',
|
||||||
SYSTEM = 'SYSTEM',
|
SYSTEM = 'SYSTEM',
|
||||||
USER_JOINED = 'USER_JOINED',
|
USER_JOINED = 'USER_JOINED',
|
||||||
|
|
|
@ -8,6 +8,7 @@ interface UserRegistrationResponse {
|
||||||
id: string;
|
id: string;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
displayColor: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatService {
|
class ChatService {
|
||||||
|
|
|
@ -22,6 +22,7 @@ Toggle dark mode on and off in the above toolbar to see how these colors look on
|
||||||
|
|
||||||
<ColorRow
|
<ColorRow
|
||||||
colors={[
|
colors={[
|
||||||
|
'theme-user-colors-0',
|
||||||
'theme-user-colors-1',
|
'theme-user-colors-1',
|
||||||
'theme-user-colors-2',
|
'theme-user-colors-2',
|
||||||
'theme-user-colors-3',
|
'theme-user-colors-3',
|
||||||
|
@ -29,6 +30,5 @@ Toggle dark mode on and off in the above toolbar to see how these colors look on
|
||||||
'theme-user-colors-5',
|
'theme-user-colors-5',
|
||||||
'theme-user-colors-6',
|
'theme-user-colors-6',
|
||||||
'theme-user-colors-7',
|
'theme-user-colors-7',
|
||||||
'theme-user-colors-8',
|
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -36,19 +36,19 @@ theme:
|
||||||
|
|
||||||
user-colors:
|
user-colors:
|
||||||
comment: 'Colors used to display chat users.'
|
comment: 'Colors used to display chat users.'
|
||||||
1:
|
0:
|
||||||
value: '{color.owncast.user.1.value}'
|
value: '{color.owncast.user.1.value}'
|
||||||
2:
|
1:
|
||||||
value: '{color.owncast.user.2.value}'
|
value: '{color.owncast.user.2.value}'
|
||||||
3:
|
2:
|
||||||
value: '{color.owncast.user.3.value}'
|
value: '{color.owncast.user.3.value}'
|
||||||
4:
|
3:
|
||||||
value: '{color.owncast.user.4.value}'
|
value: '{color.owncast.user.4.value}'
|
||||||
5:
|
4:
|
||||||
value: '{color.owncast.user.5.value}'
|
value: '{color.owncast.user.5.value}'
|
||||||
6:
|
5:
|
||||||
value: '{color.owncast.user.6.value}'
|
value: '{color.owncast.user.6.value}'
|
||||||
7:
|
6:
|
||||||
value: '{color.owncast.user.7.value}'
|
value: '{color.owncast.user.7.value}'
|
||||||
8:
|
7:
|
||||||
value: '{color.owncast.user.8.value}'
|
value: '{color.owncast.user.8.value}'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
// Do not edit directly
|
// Do not edit directly
|
||||||
// Generated on Tue, 12 Jul 2022 21:03:36 GMT
|
// Generated on Wed, 10 Aug 2022 02:31:18 GMT
|
||||||
//
|
//
|
||||||
// How to edit these values:
|
// How to edit these values:
|
||||||
// Edit the corresponding token file under the style-definitions directory
|
// Edit the corresponding token file under the style-definitions directory
|
||||||
|
@ -26,14 +26,14 @@
|
||||||
@theme-background-primary: #fffcf2; // The main background color of the page.
|
@theme-background-primary: #fffcf2; // The main background color of the page.
|
||||||
@theme-background-secondary: #f0efe4; // A secondary background color used in sections and controls.
|
@theme-background-secondary: #f0efe4; // A secondary background color used in sections and controls.
|
||||||
@theme-rounded-corners: 0.5em;
|
@theme-rounded-corners: 0.5em;
|
||||||
@theme-user-colors-1: #f40b0b;
|
@theme-user-colors-0: #f40b0b;
|
||||||
@theme-user-colors-2: #f4800b;
|
@theme-user-colors-1: #f4800b;
|
||||||
@theme-user-colors-3: #f4f40b;
|
@theme-user-colors-2: #f4f40b;
|
||||||
@theme-user-colors-4: #58f40b;
|
@theme-user-colors-3: #58f40b;
|
||||||
@theme-user-colors-5: #0bf4f4;
|
@theme-user-colors-4: #0bf4f4;
|
||||||
@theme-user-colors-6: #0ba6f4;
|
@theme-user-colors-5: #0ba6f4;
|
||||||
@theme-user-colors-7: #6666ff;
|
@theme-user-colors-6: #6666ff;
|
||||||
@theme-user-colors-8: #f40bf4;
|
@theme-user-colors-7: #f40bf4;
|
||||||
@owncast-purple: #00ff00;
|
@owncast-purple: #00ff00;
|
||||||
@owncast-purple-25: rgba(120, 113, 255, 0.25);
|
@owncast-purple-25: rgba(120, 113, 255, 0.25);
|
||||||
@owncast-purple-50: rgba(120, 113, 255, 0.5);
|
@owncast-purple-50: rgba(120, 113, 255, 0.5);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* Do not edit directly
|
* Do not edit directly
|
||||||
* Generated on Tue, 12 Jul 2022 21:03:36 GMT
|
* Generated on Wed, 10 Aug 2022 02:31:18 GMT
|
||||||
*
|
*
|
||||||
* How to edit these values:
|
* How to edit these values:
|
||||||
* Edit the corresponding token file under the style-definitions directory
|
* Edit the corresponding token file under the style-definitions directory
|
||||||
|
@ -23,23 +23,19 @@
|
||||||
--theme-text-primary: #030208; /* The color of the text in the application. */
|
--theme-text-primary: #030208; /* The color of the text in the application. */
|
||||||
--theme-text-secondary: #63638e;
|
--theme-text-secondary: #63638e;
|
||||||
--theme-text-link: #5353a6;
|
--theme-text-link: #5353a6;
|
||||||
--theme-text-body-font-family: 'Open Sans', system-ui, -apple-system, BlinkMacSystemFont,
|
--theme-text-body-font-family: 'Open Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
|
--theme-text-display-font-family: 'Poppins', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
||||||
--theme-text-display-font-family: 'Poppins', system-ui, -apple-system, BlinkMacSystemFont,
|
|
||||||
'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji',
|
|
||||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
||||||
--theme-background-primary: #fffcf2; /* The main background color of the page. */
|
--theme-background-primary: #fffcf2; /* The main background color of the page. */
|
||||||
--theme-background-secondary: #f0efe4; /* A secondary background color used in sections and controls. */
|
--theme-background-secondary: #f0efe4; /* A secondary background color used in sections and controls. */
|
||||||
--theme-rounded-corners: 0.5em;
|
--theme-rounded-corners: 0.5em;
|
||||||
--theme-user-colors-1: #f40b0b;
|
--theme-user-colors-0: #f40b0b;
|
||||||
--theme-user-colors-2: #f4800b;
|
--theme-user-colors-1: #f4800b;
|
||||||
--theme-user-colors-3: #f4f40b;
|
--theme-user-colors-2: #f4f40b;
|
||||||
--theme-user-colors-4: #58f40b;
|
--theme-user-colors-3: #58f40b;
|
||||||
--theme-user-colors-5: #0bf4f4;
|
--theme-user-colors-4: #0bf4f4;
|
||||||
--theme-user-colors-6: #0ba6f4;
|
--theme-user-colors-5: #0ba6f4;
|
||||||
--theme-user-colors-7: #6666ff;
|
--theme-user-colors-6: #6666ff;
|
||||||
--theme-user-colors-8: #f40bf4;
|
--theme-user-colors-7: #f40bf4;
|
||||||
--owncast-purple: #00ff00;
|
--owncast-purple: #00ff00;
|
||||||
--owncast-purple-25: rgba(120, 113, 255, 0.25);
|
--owncast-purple-25: rgba(120, 113, 255, 0.25);
|
||||||
--owncast-purple-50: rgba(120, 113, 255, 0.5);
|
--owncast-purple-50: rgba(120, 113, 255, 0.5);
|
||||||
|
@ -71,10 +67,6 @@
|
||||||
--color-owncast-background-primary: #fffcf2;
|
--color-owncast-background-primary: #fffcf2;
|
||||||
--color-owncast-background-secondary: #f0efe4;
|
--color-owncast-background-secondary: #f0efe4;
|
||||||
--rounded-corners: 0.5em;
|
--rounded-corners: 0.5em;
|
||||||
--font-owncast-body: 'Open Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
--font-owncast-body: 'Open Sans', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
--font-owncast-display: 'Poppins', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
'Segoe UI Symbol', 'Noto Color Emoji';
|
|
||||||
--font-owncast-display: 'Poppins', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
|
||||||
Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
|
||||||
'Segoe UI Symbol', 'Noto Color Emoji';
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue