Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webchat redesign #87

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"semi": true,
"printWidth": 100,
"arrowParens": "avoid",
"trailingComma": "none",
"endOfLine": "auto"
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added samples/.DS_Store
Binary file not shown.
30 changes: 30 additions & 0 deletions samples/feedyou/newdesign.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Chatbot</title>
</head>
<body>
<!-- href="https://cdn.feedyou.ai/webchat/latest/botchat.css
t.src = 'https://cdn.feedyou.ai/webchat/latest/botchat-es5.js';

-->
<link href="../../botchat-redesign.css" rel="stylesheet" />
<script type="text/javascript">
(function (f, y, b, o, t, s) {
(t = y.createElement(b)), (s = y.getElementsByTagName(b)[0]);
t.async = 1;
t.src = '../../botchat-es5.js';
t.onload = function () {
BotChat.App({
bot: { id: 'feedbot-demo-feedie-podmelle-lukas' },
channel: { id: 'jtuqsq' },
});
};
s.parentNode.insertBefore(t, s);
})(window, document, 'script');
</script>
<!-- druhý bot na testing: feedbot-demo-webchat, gvyddu -->
</body>
</html>
2 changes: 1 addition & 1 deletion src/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const App = async (props: AppProps, container?: HTMLElement) => {

// FEEDYOU configurable theming
if (props.theme || !container) {
const theme = { mainColor: "#D83838", ...props.theme };
const theme = { mainColor: "#0063f8", ...props.theme };
props.theme && (props.theme.enableScreenshotUpload = !!props.enableScreenshotUpload)
const themeStyle = document.createElement("style");
themeStyle.type = "text/css";
Expand Down
4 changes: 2 additions & 2 deletions src/App/templates/ExpandableTemplate/ExpandableTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class ExpandableTemplate extends React.Component<Props, State> {

doesTemplateSupportPopupMsg = () => {
const templateType = this.props.theme.template && this.props.theme.template.type
return ["expandable-knob", "sidebar"].includes(templateType)
return ["expandable-knob", "sidebar", "expandable-knob-v2", "sidebar-v2"].includes(templateType)

}

Expand All @@ -94,7 +94,7 @@ export class ExpandableTemplate extends React.Component<Props, State> {
</div>

{signature && showSignature &&
<Signature signature={signature} botId={bot.id} />
<Signature signature={signature} botId={bot.id} appProps={this.props} />
}

{this.doesTemplateSupportPopupMsg() && !initialized && popupMessage && (
Expand Down
217 changes: 185 additions & 32 deletions src/App/templates/ExpandableTemplate/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,204 @@
import * as React from 'react'
import { AppProps } from '../../App'
import { Theme } from '../../../themes'

export type Props = {
appProps: AppProps
onClick(): void
isCollapsed: boolean
}

export const Header: React.StatelessComponent<Props> = ({
appProps,
onClick,
isCollapsed,
}) => {
const {
theme: { mainColor },
header: { extraHtml },
} = appProps

const backgroundColor = mainColor || '#e51836'
const title = getTitle(appProps, isCollapsed)


return (
<div className="feedbot-header" onClick={onClick} style={{ backgroundColor }}>
<span className="feedbot-title">
{title}
</span>

{extraHtml && <span className="feedbot-extra-html" dangerouslySetInnerHTML={{ __html: extraHtml }}/>}

<a
onClick={e => e.preventDefault()}
className="feedbot-minimize"
href="#"
>_</a>
</div>
)
export type State = {
isMenuOpen: boolean;
};

export class Header extends React.Component<Props, State> {
state: State = { isMenuOpen: false };

render() {
const {
appProps: {
theme: { mainColor, template },
header: { extraHtml }
},
isCollapsed,
onClick
} = this.props;

const handlePersistentMenuToggle = () => {
this.setState(prevState => ({
isMenuOpen: !prevState.isMenuOpen
}));
};

let backgroundColor;
if (template.type !== 'expandable-knob-v2' && template.type !== 'sidebar-v2') {
backgroundColor = mainColor || '#fb584e';
}

const title = getTitle(this.props.appProps, isCollapsed);

const avatar =
template.avatar ||
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36' viewBox='0 0 36 36' fill='none'%3E%3Cpath d='M36 18c0 9.941-8.059 18-18 18S0 27.941 0 18 8.059 0 18 0s18 8.059 18 18Z' fill='%23F7F9FB'/%3E%3Cpath d='M14.024 18.026h-.003v-.005h.004l.001.002v.001l-.002.002Zm3.978 0v-.001l.001-.002v-.002h-.006v.004l.002.001h.003Zm3.976 0h-.003l-.001-.002v-.002l.001-.001h.004v.003l-.001.002Z' fill='%23385B75'/%3E%3Cpath fillRule='evenodd' clipRule='evenodd' d='M18.718 9.023a8.912 8.912 0 0 1 5.669 2.59 8.91 8.91 0 0 1-10.583 14.12l-3.073 1.182a1.274 1.274 0 0 1-1.646-1.646l1.182-3.073a8.91 8.91 0 0 1 8.45-13.173ZM14.023 17a1.024 1.024 0 1 0 0 2.047 1.024 1.024 0 0 0 0-2.047Zm3.409.172a1.023 1.023 0 1 1 1.136 1.702 1.023 1.023 0 0 1-1.136-1.702ZM21.977 17a1.023 1.023 0 1 0 0 2.047 1.023 1.023 0 0 0 0-2.047Z' fill='%23385B75'/%3E%3C/svg%3E";

const startOverIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
width="17"
height="15"
viewBox="0 0 17 15"
fill="none"
>
<path
d="M4.429 1 1 4.429l3.429 3.428"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M1 4.429h10.286a4.571 4.571 0 0 1 0 9.142H5.57"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

return (
<div className="feedbot-header" onClick={isCollapsed && onClick} style={{ backgroundColor }}>
<div className="feedbot-header-name">
{template.type === 'expandable-knob-v2' || template.type === 'sidebar-v2' ? (
<div className="feedbot-avatar" style={{ backgroundImage: `url("${avatar}")` }}></div>
) : null}
<div className="feedbot-name">
<span className="feedbot-title">{title}</span>
{template.type === 'expandable-knob-v2' || template.type === 'sidebar-v2' ? (
<span className="feedbot-supportive-title">{template.supportiveTitle}</span>
) : null}
</div>
</div>

{extraHtml && (
<span className="feedbot-extra-html" dangerouslySetInnerHTML={{ __html: extraHtml }} />
)}

<div className="feedbot-header-actions">
{(template.type === 'expandable-knob-v2' || template.type === 'sidebar-v2') &&
(checkFeedbotTestMode() || template.persistentMenu.length > 0) ? (
<div className="feedbot-persistent-menu" onClick={handlePersistentMenuToggle}>
<a className="feedbot-persistent-menu-toggle">
<svg
xmlns="http://www.w3.org/2000/svg"
width="3"
height="17"
viewBox="0 0 3 17"
fill="none"
>
<path
d="M3 1.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Zm0 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Zm0 7a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0Z"
fill="currentColor"
/>
</svg>
</a>
{this.state.isMenuOpen && (
<ul className="feedbot-persistent-menu-links">
{checkFeedbotTestMode() && (
<li className="feedbot-persistent-menu-debug">
<a onClick={handleStartOver}>
<span>Start over</span>
{startOverIcon}
</a>
</li>
)}

{template.persistentMenu.map((menuItem, index) => (
<li key={index}>
<a onClick={() => handleTriggerDialog(menuItem.dialog)}>{menuItem.title}</a>
</li>
))}
</ul>
)}
</div>
) : null}
<a
onClick={e => {
e.preventDefault();
onClick();
}}
className="feedbot-minimize"
href="#"
>
{template.type === 'expandable-knob-v2' || template.type === 'sidebar-v2' ? (
<svg
xmlns="http://www.w3.org/2000/svg"
width="26"
height="26"
viewBox="0 0 26 26"
fill="none"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M17.5303 8.46967C17.8232 8.76256 17.8232 9.23744 17.5303 9.53033L9.53033 17.5303C9.23744 17.8232 8.76256 17.8232 8.46967 17.5303C8.17678 17.2374 8.17678 16.7626 8.46967 16.4697L16.4697 8.46967C16.7626 8.17678 17.2374 8.17678 17.5303 8.46967Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.46967 8.46967C8.76256 8.17678 9.23744 8.17678 9.53033 8.46967L17.5303 16.4697C17.8232 16.7626 17.8232 17.2374 17.5303 17.5303C17.2374 17.8232 16.7626 17.8232 16.4697 17.5303L8.46967 9.53033C8.17678 9.23744 8.17678 8.76256 8.46967 8.46967Z"
fill="currentColor"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M13 1.75C6.7868 1.75 1.75 6.7868 1.75 13C1.75 19.2132 6.7868 24.25 13 24.25C19.2132 24.25 24.25 19.2132 24.25 13C24.25 6.7868 19.2132 1.75 13 1.75ZM0.25 13C0.25 5.95837 5.95837 0.25 13 0.25C20.0416 0.25 25.75 5.95837 25.75 13C25.75 20.0416 20.0416 25.75 13 25.75C5.95837 25.75 0.25 20.0416 0.25 13Z"
fill="currentColor"
/>
</svg>
) : (
'_'
)}
</a>
</div>
</div>
);
}
}

const getTitle = (props: AppProps, isCollapsed: boolean) => {
const { text, textWhenCollapsed } = props.header

const titleWhenExpanded = text || 'Chatbot'
const titleWhenCollapsed = textWhenCollapsed || titleWhenExpanded
const titleToShow = isCollapsed ? titleWhenCollapsed : titleWhenExpanded

return titleToShow
}
};

/**
* Triggers a specified dialog for the persistent menu item from Channel settings
* @param dialogId Dialog ID to be triggered on persistent menu item click
*/
const handleTriggerDialog = (dialogId: string) => {
window.dispatchEvent(new CustomEvent('feedbot:trigger-dialog', { detail: dialogId }));
};

/**
* Restart conversation via custom event
*/
const handleStartOver = () => {
window.dispatchEvent(new CustomEvent('feedbot:start-over'));
};

/**
* Check URL if test mode is being used (#feedbot-test-mode)
* @returns Boolean
*/
const checkFeedbotTestMode = (): boolean => {
return window.location.hash === '#feedbot-test-mode';
};

export type HeaderProps = Props
Loading