chat-ui-kit-styles icon indicating copy to clipboard operation
chat-ui-kit-styles copied to clipboard

Documentation for custom styles

Open chloe-schoreisz opened this issue 4 years ago • 22 comments

I would love to see some documentations on how to stylized the different components (eg. colors, fonts, change of icons, etc)

chloe-schoreisz avatar Jul 08 '21 18:07 chloe-schoreisz

For anyone looking, we figured out a way: We created our own main.scss file, that looks like this:

@charset "utf-8";
@import "./variables";
@import "./helpers/mixins";
@import "./helpers/functions";
@import "@chatscope/chat-ui-kit-styles/themes/default/main.scss";
  • mixins and functions are copy pasted from @chatscope/chat-ui-kit-styles/themes/helpers/mixins and @chatscope/chat-ui-kit-styles/themes/helpers/functions.
  • variables is initially copy pasted from @chatscope/chat-ui-kit-styles/themes/variables, and then updated with the appropriate colors for the different component (keeping the !default for the color variables)
  • We then imported the main.scss into our app (we're using nextjs, which supports scss direct imports) ⚠️ I'm still getting issues for stylizing the send button and the input box.

This will work if your app supports scss. You should compile this to css if it doesn't.

chloe-schoreisz avatar Aug 02 '21 13:08 chloe-schoreisz

@chloe-schoreisz Thank you for your explanation. It's awesome that somebody helps me maintaining the project :)

And here is the solution that I use in my projects based on Create React App.

Assuming your app supports scss (e.g. CRA, NEXTjs).

project_root/src/themes/default/_chat-overrides.scss:

/* The path depends on the current location of the scss file */
@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/variables";

// Here you can override variables from the imported file above. Check its source for a list of available variables
$main-container-border: 0;
$color-text: red;
$conversation-color: pink;

// ... and so on 

project_root/src/themes/default/main.scss:

@charset "utf-8";
@import "./chat-overrides";
@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/main";

// ... any other imports 

project_root/src/App.js:

import './themes/default/main.scss';
import MyApp from "./MyApp"

function App() {
 return (<MyApp />);
}
export default App;

supersnager avatar Sep 22 '21 19:09 supersnager

@chloe-schoreisz

I'm still getting issues for stylizing the send button and the input box

What's your issue with styling these items??

supersnager avatar Sep 22 '21 20:09 supersnager

I was trying to obtain a specific color for the SendButton through the custom scss file. I could not change it from there, and I tried all the variables. The only way I was able to change the color was by implementing my own CustomMessageInput, and hardcode the color in the styling.

// CustomMessageInput.tsx

                         <MessageInput
				ref={...}
				onSend={sendMessage}
				onChange={(_: string, textContent: string) => {
					setMessageInputValue(textContent);
				}}
				value={messageInputValue}
				sendButton={false}
				attachButton={false}
			/>
			<SendButton
				onClick={() => sendMessage(messageInputValue)}
				style={{
					color: '#0C3276',
					backgroundColor: '#C7FED2',
					width: '48px',
					height: '45px'
					
				}}
			/>

chloe-schoreisz avatar Sep 23 '21 13:09 chloe-schoreisz

I was also trying to update the icon of the send button, but couldn't find a way

chloe-schoreisz avatar Sep 23 '21 13:09 chloe-schoreisz

@chloe-schoreisz Your solution is fine, especially when there is a need to make more changes than simply color change.

However, the send button color should be changeable by overriding $send-button-color variable https://github.com/chatscope/chat-ui-kit-styles/blob/6823363a99ef2a6be7eaf6fadd17599b4ad99138/themes/default/_variables.scss#L180 but now I see there is a bug :sweat_smile: (missing !default) I ~~will fix~~ fixed it in here: https://github.com/chatscope/chat-ui-kit-styles/issues/8

supersnager avatar Sep 23 '21 18:09 supersnager

Just gave this a try in NextJS with my own project and ran into some issues with the styles not applying despite following the instructions that @supersnager laid out so thought it would be good to share here. The import of the variables.scss file in your custom.scss styles should be happening after your actual custom variables are assigned. We referred to this article to figure this out. Unfortunately, we weren't able to get modular styles to work (in attempts to follow NextJS conventions), having to import and apply the styles globally on _app.tsx.

$color-text: red;

@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/variables";
@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/main";

Not sure if this is a quirk of NextJS, but would be interested to know. Thank you!

sh1ggy avatar Mar 26 '23 10:03 sh1ggy

/* The path depends on the current location of the scss file */
@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/variables";

// Here you can override variables from the imported file above. Check its source for a list of available variables
$main-container-border: 0;
$color-text: red;
$conversation-color: pink;

Using this approach, I manage to change some of the variables (i.e. the default font family), but only if i replace !default with !important, and that's not possible with all variables (i.e. the color variables – they throw an error if I use !important – do you know a way around?

axelferdinand avatar May 04 '23 14:05 axelferdinand

@axelferdinand Please share the code (e.g. your _chat-overrides.scss ), how do you override values? !default and !important are used for different things, when overriding, you don't use !default.

supersnager avatar May 04 '23 20:05 supersnager

@supersnager Sure!

_chat-overrides.scss

// Default font family
//

$default-font-family: 'Clan', Helvetica, sans-serif !important;

// Colors
//

$color-primary: #000 !default;
$color-primary-light: #FFF !default;
$color-primary-dark: #000 !default;
$color-primary-dark: #000 !default;

main.scss

@charset "utf-8";

@font-face {
  font-family: 'Clan';
  src: url('fonts/ClanOffc-News.woff2') format('woff2');
       font-weight: normal;
       font-style: normal;
}

@font-face {
  font-family: 'Clan';
  src: url('fonts/ClanOffc-Bold.woff2') format('woff2');
       font-weight: bold;
       font-style: bold;
}

@import "./chat-overrides";
@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/main";

_app.txt

import type { AppProps } from "next/app";
import { FpjsProvider } from "@fingerprintjs/fingerprintjs-pro-react";
import { configureAbly } from "@ably-labs/react-hooks";
import '../themes/default/main.scss';

const prefix = process.env.API_ROOT || "";

const clientId =
  Math.random().toString(36).substring(2, 15) +
  Math.random().toString(36).substring(2, 15);

configureAbly({
  authUrl: `${prefix}/api/createTokenRequest?clientId=${clientId}`,
  clientId: clientId,
});

const fpjsPublicApiKey = process.env.FINGERPRINT as string;

export default function App({ Component, pageProps }: AppProps) {
  return (
    <FpjsProvider
      loadOptions={{
        apiKey: fpjsPublicApiKey,
      }}
    >
      <Component {...pageProps} />
    </FpjsProvider>
  );
}

index.txs

import Head from "next/head";
import { useState } from "react";
import { useVisitorData } from "@fingerprintjs/fingerprintjs-pro-react";
import ReactMarkdown from "react-markdown";
import * as timeago from "timeago.js";

import styles from "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";

import {
  MainContainer,
  ChatContainer,
  MessageList,
  Message,
  MessageInput,
  ConversationHeader,
  TypingIndicator,
} from "@chatscope/chat-ui-kit-react";

import { useChannel } from "@ably-labs/react-hooks";
import { Types } from "ably";

type ConversationEntry = {
  message: string;
  speaker: "bot" | "user";
  date: Date;
  id?: string;
};

type request = {
  prompt: string;
};

const updateChatbotMessage = (
  conversation: ConversationEntry[],
  message: Types.Message
): ConversationEntry[] => {
  const interactionId = message.data.interactionId;

  const updatedConversation = conversation.reduce(
    (acc: ConversationEntry[], e: ConversationEntry) => [
      ...acc,
      e.id === interactionId
        ? { ...e, message: e.message + message.data.token }
        : e,
    ],
    []
  );

  return conversation.some((e) => e.id === interactionId)
    ? updatedConversation
    : [
        ...updatedConversation,
        {
          id: interactionId,
          message: message.data.token,
          speaker: "bot",
          date: new Date(),
        },
      ];
};

export default function Home() {
  const [text, setText] = useState("");
  const [extendedResult, updateExtendedResult] = useState(false);
  const [conversation, setConversation] = useState<ConversationEntry[]>([]);
  const [botIsTyping, setBotIsTyping] = useState(false);
  const [statusMessage, setStatusMessage] = useState("Skriv spørsmålet ditt...");

  const { isLoading, data: visitorData } = useVisitorData(
    { extendedResult },
    { immediate: true }
  );

  useChannel(visitorData?.visitorId! || "default", (message) => {
    switch (message.data.event) {
      case "response":
        setConversation((state) => updateChatbotMessage(state, message));
        break;
      case "status":
        setStatusMessage(message.data.message);
        break;
      case "responseEnd":
      default:
        setBotIsTyping(false);
        setStatusMessage("Waiting for query...");
    }
  });

  const submit = async () => {
    setConversation((state) => [
      ...state,
      {
        message: text,
        speaker: "user",
        date: new Date(),
      },
    ]);
    try {
      setBotIsTyping(true);
      const response = await fetch("/api/chat", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ prompt: text, userId: visitorData?.visitorId }),
      });

      await response.json();
    } catch (error) {
      console.error("Error submitting message:", error);
    } finally {
      setBotIsTyping(false);
    }
    setText("");
  };

  return (
    <>
      <Head>
        <title>Virke</title>
        <meta name="description" content="Generated by create next app" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main className={styles.main}>
        <div
          style={{ position: "relative", height: "98vh", overflow: "hidden" }}
        >
          <MainContainer>
            <ChatContainer>
              <ConversationHeader>
                <ConversationHeader.Actions></ConversationHeader.Actions>
                <ConversationHeader.Content
                  userName="Få hjelp med det juridiske innholdet på virke.no"
                  info={statusMessage}
                />
              </ConversationHeader>

              <MessageList
                typingIndicator={
                  botIsTyping ? (
                    <TypingIndicator content="Vi jobber med saken..." />
                  ) : null
                }
              >
                {conversation.map((entry, index) => {
                  return (
                    <Message
                      key={index}
                      style={{ width: "90%" }}
                      model={{
                        type: "custom",
                        sender: entry.speaker,
                        position: "single",
                        direction:
                          entry.speaker === "bot" ? "incoming" : "outgoing",
                      }}
                    >
                      <Message.CustomContent>
                        <ReactMarkdown>{entry.message}</ReactMarkdown>
                      </Message.CustomContent>
                      <Message.Footer
                        sentTime={timeago.format(entry.date)}
                        sender={entry.speaker === "bot" ? "Virke" : "Du"}
                      />
                    </Message>
                  );
                })}
              </MessageList>
              <MessageInput
                placeholder="Skriv her..."
                onSend={submit}
                onChange={(e, text) => {
                  setText(text);
                }}
                sendButton={true}
                autoFocus
                disabled={isLoading}
              />
            </ChatContainer>
          </MainContainer>
        </div>
      </main>
    </>
  );
}

axelferdinand avatar May 05 '23 11:05 axelferdinand

@axelferdinand

Try to remove !default in _chat-overrides.scss

Change this:

$color-primary: #000 !default;
$color-primary-light: #FFF !default;
$color-primary-dark: #000 !default;
$color-primary-dark: #000 !default;

to this:

$color-primary: #000;
$color-primary-light: #FFF;
$color-primary-dark: #000;
$color-primary-dark: #000;

supersnager avatar May 06 '23 14:05 supersnager

@supersnager I tried that, but it didn't work, unfortunately.

My console says this:

wait  - compiling...
event - compiled successfully in 426 ms (434 modules)

...but the colors (or other variables) doesn't update. This is the only thing that will update:

$default-font-family: 'Clan', Helvetica, sans-serif !important;

axelferdinand avatar May 07 '23 11:05 axelferdinand

@axelferdinand I think I have found the source of the problem.

Try to remove the following line from the index.tsx:

import styles from "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";

and remove className from:

<main className={styles.main}>

Your example is not working because you import main.scss which includes:

@import "./chat-overrides";
@import "../../../node_modules/@chatscope/chat-ui-kit-styles/themes/default/main";

and next you import @chatscope/chat-ui-kit-styles/dist/default/styles.min.css The import of the minimized styles overrides a theme imported earlier.

After importing main.scss all chatscope styles are ready because the theme is built in your app. So importing @chatscope/chat-ui-kit-styles/dist/default/styles.min.css is not necessary.

BTW in the @chatscope/chat-ui-kit-styles/dist/default/styles.min.css there is no "main" class.

supersnager avatar May 07 '23 20:05 supersnager

@supersnager That did indeed work!! Thank you so much!!

axelferdinand avatar May 08 '23 11:05 axelferdinand

Hello I was wondering if there is any way possible to style the chat-ui-kit using the tailwind? I tried with the MainContainer, ChatContainer, MessageList and it worked... However when I tried to style the MessageInput and the MessageSeperator using tailwind I couldn't... so I was wondering if you can help me with that please?

dolce-emmy avatar May 26 '23 18:05 dolce-emmy

@dolce-emmy What exactly do you want to do?

supersnager avatar May 27 '23 22:05 supersnager

I want dark theme

abuvanth avatar Aug 31 '23 11:08 abuvanth

I want dark theme

Me too. It'd be nice to just add a dark mode functionality in the kit itself @supersnager

FatGuyy avatar Oct 29 '23 04:10 FatGuyy

Any updated guide on how to change the style?

hhussein97 avatar Nov 14 '23 23:11 hhussein97

Just take these classnames to your styles.css and change accordingly. This overrides the default styles.

div .cs-message-list__typing-indicator-container div { color: #6d4700; }

div .cs-main-container, div .cs-chat-container .cs-message-input { border: 0px; }

div .cs-message--incoming .cs-message__content, div .cs-chat-container .cs-message-input, div .ps__thumb-y, div .ps__rail-y:hover .ps__thumb-y, div .ps__rail-y:active .ps__thumb-y { background-color: #ffc436; }

div .cs-message-input__content-editor, div .cs-message-input__content-editor-wrapper, div .cs-message-list, div .ps__rail-y:hover, div .ps .ps__rail-y:hover, div .ps__rail-y { background-color: #ffebbb; }

div .cs-message--outgoing .cs-message__content { background-color: #ffa552; }

div .cs-typing-indicator__dot { background-color: #6d4700; }

ragib1803 avatar Mar 07 '24 23:03 ragib1803

Next.js

// src/components/chat.scss

@charset "utf-8";

$color-text: white;
$blue: #2894CD;
$green: #61AD4A;
$message-content-incoming-bg-color: $blue;
$message-content-outgoing-bg-color: #444;
$color-secondary: #555;
$message-input-bg-color: white;
$message-input-content-editor-wrapper-bg-color: white;
$message-input-content-editor-color: black;
$button-attachment-color: white;
$button-send-color: $green;
$message-group-header-padding: 0.5rem;
$message-list-scroll-wrapper-padding: 1.2em 1.2em 0 0.8em;

@import "@chatscope/chat-ui-kit-styles/themes/default/variables";

@import "@chatscope/chat-ui-kit-styles/themes/default/main";

In your chat component:

import './chat.scss';

jasonhargrove avatar Aug 25 '24 20:08 jasonhargrove

I'm trying to use it on backstage and any of those solutions work at all

Thauanny avatar Sep 17 '24 15:09 Thauanny