mirror of
https://github.com/Safe-Support-Chat/ocrcc-chatbox
synced 2024-11-01 00:55:26 +00:00
wcag compliance
This commit is contained in:
parent
8f9f0fc8b0
commit
08981fd444
@ -6,15 +6,15 @@
|
|||||||
font-family: $theme-font;
|
font-family: $theme-font;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 50vh;
|
height: 60vh;
|
||||||
|
max-height: 100vh;
|
||||||
|
min-height: 180px;
|
||||||
border: 1px solid $theme-color;
|
border: 1px solid $theme-color;
|
||||||
|
|
||||||
.message-window {
|
.message-window {
|
||||||
background-color: $light-color;
|
background-color: $light-color;
|
||||||
flex: 1 0 auto;
|
flex: 1 1 auto;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
height: 300px;
|
|
||||||
max-height: 100%;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column-reverse;
|
flex-direction: column-reverse;
|
||||||
@ -37,6 +37,7 @@
|
|||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
border: 1px solid $theme-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.from-me {
|
&.from-me {
|
||||||
@ -58,7 +59,6 @@
|
|||||||
.text {
|
.text {
|
||||||
background-color: $white;
|
background-color: $white;
|
||||||
color: $dark-color;
|
color: $dark-color;
|
||||||
border: 1px solid $theme-color;
|
|
||||||
border-radius: 15px 15px 15px 0;
|
border-radius: 15px 15px 15px 0;
|
||||||
margin-right: 10%;
|
margin-right: 10%;
|
||||||
}
|
}
|
||||||
@ -101,4 +101,5 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
61
src/components/_dark_mode.scss
Normal file
61
src/components/_dark_mode.scss
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.dock {
|
||||||
|
background: $dark-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
color: $dark-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ocrcc-chatbox {
|
||||||
|
border: 1px solid $dark-theme-color;
|
||||||
|
|
||||||
|
.widget-header {
|
||||||
|
background-color: $dark-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-window {
|
||||||
|
background-color: $dark-background-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notices {
|
||||||
|
color: transparentize($light-text-color, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
.text {
|
||||||
|
border: 1px solid $light-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.from-me {
|
||||||
|
.text {
|
||||||
|
background-color: $light-background-color;
|
||||||
|
color: $dark-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.from-support {
|
||||||
|
.text {
|
||||||
|
background-color: $dark-theme-color;
|
||||||
|
color: $light-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-window {
|
||||||
|
form {
|
||||||
|
border-top: 1px solid $dark-theme-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
background-color: $light-background-color;
|
||||||
|
color: $dark-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="submit"] {
|
||||||
|
background-color: $dark-theme-color;
|
||||||
|
color: $light-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@
|
|||||||
animation: load7 1.8s infinite ease-in-out;
|
animation: load7 1.8s infinite ease-in-out;
|
||||||
}
|
}
|
||||||
.loader {
|
.loader {
|
||||||
color: $teal; /*purple*/
|
color: $theme-color;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
$light-color: #FFF8F0;
|
$light-color: #f6faff;
|
||||||
$dark-color: #22333B;
|
$dark-color: #04090F;
|
||||||
$yellow: #FFFACD;
|
$yellow: #FFFACD;
|
||||||
$teal: #008080;
|
$dark-blue: #2660A4;
|
||||||
$white: #ffffff;
|
$white: #ffffff;
|
||||||
$highlight-color: $yellow;
|
$highlight-color: $yellow;
|
||||||
$theme-color: $teal;
|
$theme-color: $dark-blue;
|
||||||
$theme-font: 'Assistant', 'Helvetica', sans-serif;
|
$theme-font: 'Assistant', 'Helvetica', sans-serif;
|
||||||
|
|
||||||
|
/* Dark mode colors */
|
||||||
|
|
||||||
|
$dark-background-color: #0F1116;
|
||||||
|
$light-background-color: #ffffff;
|
||||||
|
$light-text-color: #ffffff;
|
||||||
|
$dark-text-color: #0F1116;
|
||||||
|
$dark-theme-color: #333C4B;
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
@import "variables";
|
|
||||||
@import "loader";
|
|
||||||
@import "chat";
|
|
||||||
|
|
||||||
@keyframes slideInUp {
|
@keyframes slideInUp {
|
||||||
from {
|
from {
|
@ -179,6 +179,13 @@ class ChatBox extends React.Component {
|
|||||||
this.setState({ messages })
|
this.setState({ messages })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleEscape = (e) => {
|
||||||
|
if (e.keyCode === 27 && this.props.opened) {
|
||||||
|
this.props.handleToggleOpen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
if (prevState.client !== this.state.client) {
|
if (prevState.client !== this.state.client) {
|
||||||
this.createRoom()
|
this.createRoom()
|
||||||
@ -231,7 +238,12 @@ class ChatBox extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.addEventListener("keydown", this.handleEscape, false);
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
document.removeEventListener("keydown", this.handleEscape, false);
|
||||||
this.leaveRoom();
|
this.leaveRoom();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,12 +265,13 @@ class ChatBox extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
const { ready, messages, inputValue, userId, isRoomEncrypted } = this.state;
|
const { ready, messages, inputValue, userId, isRoomEncrypted } = this.state;
|
||||||
const { opened, handleToggleOpen } = this.props;
|
const { opened, handleToggleOpen } = this.props;
|
||||||
|
const inputLabel = 'Send a message...'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="ocrcc-chatbox">
|
<div id="ocrcc-chatbox" aria-haspopup="dialog" aria-label="Open support chat">
|
||||||
<div className="widget-header">
|
<div className="widget-header">
|
||||||
<div className="widget-header-title">
|
<div className="widget-header-title">
|
||||||
{ isRoomEncrypted && <span>🔒</span> } Support Chat
|
Support Chat
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -284,7 +297,7 @@ class ChatBox extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
<div className="notices">
|
<div className="notices">
|
||||||
{
|
{
|
||||||
isRoomEncrypted && <div>Messages in this chat are secured with end-to-end encryption.</div>
|
isRoomEncrypted && <div role="status">Messages in this chat are secured with end-to-end encryption.</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -294,6 +307,8 @@ class ChatBox extends React.Component {
|
|||||||
type="text"
|
type="text"
|
||||||
onChange={this.handleInputChange}
|
onChange={this.handleInputChange}
|
||||||
value={inputValue}
|
value={inputValue}
|
||||||
|
aria-label={inputLabel}
|
||||||
|
placeholder={inputLabel}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
ref={this.chatboxInput}
|
ref={this.chatboxInput}
|
||||||
/>
|
/>
|
||||||
|
5
src/components/styles.scss
Normal file
5
src/components/styles.scss
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@import "variables";
|
||||||
|
@import "loader";
|
||||||
|
@import "widget";
|
||||||
|
@import "chat";
|
||||||
|
@import "dark_mode";
|
@ -1,7 +1,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Transition } from 'react-transition-group';
|
import { Transition } from 'react-transition-group';
|
||||||
import Chatbox from './chatbox';
|
import Chatbox from './chatbox';
|
||||||
import './widget.scss';
|
import './styles.scss';
|
||||||
|
|
||||||
class Widget extends Component {
|
class Widget extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -36,10 +36,10 @@ class Widget extends Component {
|
|||||||
const { opened, showDock } = this.state;
|
const { opened, showDock } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="docked-widget">
|
<div className="docked-widget" role="complementary">
|
||||||
<Transition in={opened} timeout={250} onExited={this.handleWidgetExit}>
|
<Transition in={opened} timeout={250} onExited={this.handleWidgetExit}>
|
||||||
{(status) => (
|
{(status) => (
|
||||||
<div className={`widget widget-${status}`}>
|
<div className={`widget widget-${status}`} aria-hidden={!opened}>
|
||||||
<Chatbox
|
<Chatbox
|
||||||
handleToggleOpen={this.handleToggleOpen}
|
handleToggleOpen={this.handleToggleOpen}
|
||||||
opened={opened}
|
opened={opened}
|
||||||
@ -55,9 +55,10 @@ class Widget extends Component {
|
|||||||
className="dock"
|
className="dock"
|
||||||
onClick={this.handleToggleOpen}
|
onClick={this.handleToggleOpen}
|
||||||
onKeyPress={this.handleToggleOpen}
|
onKeyPress={this.handleToggleOpen}
|
||||||
|
aria-labelledby="open-chatbox-label"
|
||||||
>
|
>
|
||||||
<span>Open support chat</span>
|
<span id="open-chatbox-label">Open support chat</span>
|
||||||
<span className={`arrow ${opened ? 'opened' : 'closed'}`}>⌃</span>
|
<span className={`arrow ${opened ? 'opened' : 'closed'}`} aria-label={`${opened ? 'Close' : 'Open'} support chat window`}>⌃</span>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user