mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
updates to selection bubbles and added voices
This commit is contained in:
1 parent
d3eb7b0de2
commit
f9581eb411
6 files changed
+154
-44
No files matched your search
@@ -22,6 +22,7 @@ interface AlertProps {
|
||||
icon?: IconProp;
|
||||
link?: string;
|
||||
linkText?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function Alert({
|
||||
@@ -32,6 +33,7 @@ function Alert({
|
||||
icon,
|
||||
linkText,
|
||||
link,
|
||||
className,
|
||||
}: AlertProps) {
|
||||
const [show, setShow] = useState<boolean>(() => {
|
||||
const closedAt = localStorage.getItem(`alertClosedAt_${id}`);
|
||||
@@ -55,7 +57,9 @@ function Alert({
|
||||
<>
|
||||
{show && (
|
||||
<div
|
||||
className={`alert alert-${alertVariant} alert-dismissible fade show`}
|
||||
className={`alert alert-${alertVariant} alert-dismissible fade show ${
|
||||
className && className
|
||||
}`.trim()}
|
||||
role="alert"
|
||||
>
|
||||
{icon && <FontAwesomeIcon icon={icon} className="me-2" />}
|
||||
|
||||
@@ -1,11 +1,59 @@
|
||||
@import "scss/colours.scss";
|
||||
|
||||
.selection-bubbles-wrapper {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transition: all 0.4s;
|
||||
|
||||
.scroll-indicator {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
top: 50%;
|
||||
right: 0px;
|
||||
transform: translateY(-50%);
|
||||
color: rgba($white, 0.2);
|
||||
pointer-events: none;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 80px;
|
||||
background: linear-gradient(to right, rgba($panel, 0), $panel);
|
||||
pointer-events: none;
|
||||
display: none;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
&.show-gradient:after {
|
||||
display: block;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
}
|
||||
|
||||
.selection-bubbles {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: none;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
flex-wrap: wrap;
|
||||
justify-content: start;
|
||||
overflow-x: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble-button {
|
||||
flex: 0 0 auto;
|
||||
border: 2px solid darken($secondary, 3%);
|
||||
padding: 8px 16px;
|
||||
border-radius: 0.5rem;
|
||||
@@ -16,6 +64,7 @@
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
color: rgba($white, 0.75);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.bubble-button:hover {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import "./SelectionBubbles.scss";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faChevronRight } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface SelectionBubbleProps {
|
||||
options: string[];
|
||||
@@ -14,6 +16,8 @@ export default function SelectionBubbles({
|
||||
const [selectedOption, setSelectedOption] = useState<string | null>(
|
||||
options.length > 0 ? options[0] : null
|
||||
);
|
||||
const [showGradient, setShowGradient] = useState(true);
|
||||
const bubblesRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleSelect = (
|
||||
event: React.MouseEvent<HTMLButtonElement>,
|
||||
@@ -31,19 +35,62 @@ export default function SelectionBubbles({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const handleScroll = () => {
|
||||
if (bubblesRef.current) {
|
||||
const { scrollLeft, scrollWidth, clientWidth } = bubblesRef.current;
|
||||
const isAtEnd = scrollWidth - Math.round(scrollLeft + clientWidth) <= 1; // Adjust tolerance as needed
|
||||
setShowGradient(!isAtEnd);
|
||||
}
|
||||
};
|
||||
|
||||
const checkForOverflowContent = () => {
|
||||
if (bubblesRef.current) {
|
||||
const { scrollWidth, clientWidth } = bubblesRef.current;
|
||||
const isOverflowing = scrollWidth > clientWidth;
|
||||
setShowGradient(isOverflowing);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
checkForOverflowContent();
|
||||
window.addEventListener("resize", checkForOverflowContent);
|
||||
return () => window.removeEventListener("resize", checkForOverflowContent);
|
||||
}, [options]);
|
||||
|
||||
useEffect(() => {
|
||||
if (bubblesRef.current) {
|
||||
bubblesRef.current.addEventListener("scroll", handleScroll);
|
||||
return () =>
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
bubblesRef.current?.removeEventListener("scroll", handleScroll);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="selection-bubbles">
|
||||
{options.map(option => (
|
||||
<button
|
||||
key={option}
|
||||
className={`bubble-button ${
|
||||
selectedOption === option ? "selected" : ""
|
||||
}`}
|
||||
onClick={event => handleSelect(event, option)}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
<div
|
||||
className={`selection-bubbles-wrapper ${
|
||||
showGradient ? "show-gradient" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="selection-bubbles" ref={bubblesRef}>
|
||||
{options.map(option => (
|
||||
<button
|
||||
key={option}
|
||||
className={`bubble-button ${
|
||||
selectedOption === option ? "selected" : ""
|
||||
}`}
|
||||
onClick={event => handleSelect(event, option)}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
{showGradient && (
|
||||
<FontAwesomeIcon
|
||||
icon={faChevronRight}
|
||||
className="scroll-indicator fs-5"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -213,15 +213,15 @@ export default function TopNav({
|
||||
<div className="topbar-nav-center">
|
||||
{/* Search Bar */}
|
||||
<div className="d-none d-lg-block">
|
||||
{(!isOnLandingPage ||
|
||||
loggedIn ||
|
||||
(isOnLandingPage && isScrolled)) && (
|
||||
{(!isOnLandingPage && !isOnLoginOrSignUpPage) ||
|
||||
(loggedIn && !isOnLoginOrSignUpPage) ||
|
||||
(isOnLandingPage && isScrolled && !isOnLoginOrSignUpPage) ? (
|
||||
<SearchBar
|
||||
onFocus={onFocusHandler}
|
||||
onBlur={onBlurHandler}
|
||||
isFocused={isFocused}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -271,22 +271,27 @@ export default function TopNav({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
icon={faClipboardList}
|
||||
variant="secondary"
|
||||
small={true}
|
||||
label="My Jobs"
|
||||
onClick={openModal}
|
||||
className="d-lg-none"
|
||||
/>
|
||||
<Button
|
||||
icon={faSearch}
|
||||
variant="secondary"
|
||||
small={true}
|
||||
square={true}
|
||||
onClick={handleSearchButtonClick}
|
||||
className="d-lg-none"
|
||||
/>
|
||||
{!showNavItem && (
|
||||
<>
|
||||
<Button
|
||||
icon={faClipboardList}
|
||||
variant="secondary"
|
||||
small={true}
|
||||
label="My Jobs"
|
||||
onClick={openModal}
|
||||
className="d-lg-none"
|
||||
/>
|
||||
<Button
|
||||
icon={faSearch}
|
||||
variant="secondary"
|
||||
small={true}
|
||||
square={true}
|
||||
onClick={handleSearchButtonClick}
|
||||
className="d-lg-none"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Button
|
||||
icon={menuButtonIcon}
|
||||
variant="secondary"
|
||||
|
||||
@@ -38,16 +38,19 @@ export default function FakeYouLandingHeader({
|
||||
|
||||
return (
|
||||
<div className="d-flex flex-column fy-header">
|
||||
<Alert
|
||||
id="text-to-image-alert"
|
||||
icon={faSparkles}
|
||||
message={t("alertTtiText")}
|
||||
alertVariant="new"
|
||||
link="/text-to-image"
|
||||
linkText={t("alertTtiCta")}
|
||||
/>
|
||||
<Panel clear={true}>
|
||||
<Alert
|
||||
id="text-to-image-alert"
|
||||
icon={faSparkles}
|
||||
message={t("alertTtiText")}
|
||||
alertVariant="new"
|
||||
link="/text-to-image"
|
||||
linkText={t("alertTtiCta")}
|
||||
className="my-3"
|
||||
/>
|
||||
</Panel>
|
||||
|
||||
<div className="my-5 py-5">
|
||||
<div className="my-lg-5 py-lg-5 pt-4 pb-5">
|
||||
<div className="row g-5">
|
||||
<div className="col-12 col-lg-6 order-lg-2">
|
||||
<LandingDemo
|
||||
|
||||
+3
-1
@@ -84,6 +84,8 @@ export default function LandingDemo({
|
||||
Rick: "weight_0f762jdzgsy1dhpb86qxy4ssm",
|
||||
Mickey: "weight_sfyjyr67ag1647xs0r7gmvkks",
|
||||
Eric: "weight_h8ebh6fyjyrr1vsjregw6yz8y",
|
||||
Stan: "weight_0cg1294gaf52c7rh0vz7a2ger",
|
||||
Zelda: "weight_b8rncypy7gw6nb0wthnwe2kk4",
|
||||
"Angry Male": "weight_hehgvegadf08mfp5rzd69dmh4",
|
||||
};
|
||||
|
||||
@@ -199,7 +201,7 @@ export default function LandingDemo({
|
||||
if (hasMessage) {
|
||||
maybeError = (
|
||||
<div
|
||||
className="alert alert-primary alert-dismissible fade show m-0"
|
||||
className="alert alert-primary alert-dismissible fade show mt-3"
|
||||
role="alert"
|
||||
>
|
||||
<button
|
||||
|
||||
Reference in new issue
Block a user