mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-22 16:48:23 +01:00
rating notification
This commit is contained in:
parent
416ba8d5da
commit
d4ee83dcb7
@ -6,6 +6,7 @@ import { FloatingPortal, useFloating, useInteractions } from "@floating-ui/react
|
|||||||
import { useAtomValue } from "jotai";
|
import { useAtomValue } from "jotai";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { NotificationItem } from "./notificationitem";
|
import { NotificationItem } from "./notificationitem";
|
||||||
|
import { RatingBubble } from "./ratingbubble";
|
||||||
import { useNotification } from "./usenotification";
|
import { useNotification } from "./usenotification";
|
||||||
|
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
@ -16,6 +17,7 @@ const NotificationBubbles = () => {
|
|||||||
notifications,
|
notifications,
|
||||||
hoveredId,
|
hoveredId,
|
||||||
hideNotification,
|
hideNotification,
|
||||||
|
removeNotification,
|
||||||
copyNotification,
|
copyNotification,
|
||||||
handleActionClick,
|
handleActionClick,
|
||||||
formatTimestamp,
|
formatTimestamp,
|
||||||
@ -60,6 +62,15 @@ const NotificationBubbles = () => {
|
|||||||
>
|
>
|
||||||
{notifications.map((notif) => {
|
{notifications.map((notif) => {
|
||||||
if (notif.hidden) return null;
|
if (notif.hidden) return null;
|
||||||
|
if (notif.componentType === "rating") {
|
||||||
|
return (
|
||||||
|
<RatingBubble
|
||||||
|
key={notif.id}
|
||||||
|
notification={notif}
|
||||||
|
onRemove={removeNotification}
|
||||||
|
></RatingBubble>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<NotificationItem
|
<NotificationItem
|
||||||
key={notif.id}
|
key={notif.id}
|
||||||
|
@ -29,8 +29,8 @@ const NotificationItem = ({
|
|||||||
onMouseEnter,
|
onMouseEnter,
|
||||||
onMouseLeave,
|
onMouseLeave,
|
||||||
}: NotificationItemProps) => {
|
}: NotificationItemProps) => {
|
||||||
const { id, title, message, icon, type, timestamp, persistent, actions } = notification;
|
const { id, title, message, icon, statusType, timestamp, persistent, actions } = notification;
|
||||||
const color = type === "error" ? "red" : type === "warning" ? "yellow" : "green";
|
const color = statusType === "error" ? "red" : statusType === "warning" ? "yellow" : "green";
|
||||||
const nIcon = icon ? icon : "bell";
|
const nIcon = icon ? icon : "bell";
|
||||||
|
|
||||||
const renderCloseButton = () => {
|
const renderCloseButton = () => {
|
||||||
|
@ -37,8 +37,8 @@ const NotificationPopover = () => {
|
|||||||
setNotificationPopoverMode(!notificationPopoverMode);
|
setNotificationPopoverMode(!notificationPopoverMode);
|
||||||
}, [notificationPopoverMode]);
|
}, [notificationPopoverMode]);
|
||||||
|
|
||||||
const hasErrors = notifications.some((n) => n.type === "error");
|
const hasErrors = notifications.some((n) => n.statusType === "error");
|
||||||
const hasUpdate = notifications.some((n) => n.type === "update");
|
const hasUpdate = notifications.some((n) => n.statusType === "update");
|
||||||
|
|
||||||
const addOnClassNames = hasUpdate ? "solid green" : hasErrors ? "solid red" : "ghost grey";
|
const addOnClassNames = hasUpdate ? "solid green" : hasErrors ? "solid red" : "ghost grey";
|
||||||
|
|
||||||
|
48
frontend/app/notification/ratingbubble.less
Normal file
48
frontend/app/notification/ratingbubble.less
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
.notification-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 18px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
color: var(--success-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-message {
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating-bubble {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
width: 380px;
|
||||||
|
padding: 16px 24px 16px 16px;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 0.5px solid rgba(255, 255, 255, 0.12);
|
||||||
|
background: #232323;
|
||||||
|
box-shadow: 0px 8px 32px 0px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-inner {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
column-gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hovered {
|
||||||
|
background: #292929;
|
||||||
|
}
|
65
frontend/app/notification/ratingbubble.tsx
Normal file
65
frontend/app/notification/ratingbubble.tsx
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2024, Command Line Inc.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import { Button } from "@/element/button";
|
||||||
|
import { makeIconClass } from "@/util/util";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import "./ratingbubble.less";
|
||||||
|
|
||||||
|
interface RatingBubbleProps {
|
||||||
|
notification: NotificationType;
|
||||||
|
onRemove: (id: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RatingBubble = ({ notification, onRemove }: RatingBubbleProps) => {
|
||||||
|
const { id, title, message } = notification;
|
||||||
|
const [hoveredButtons, setHoveredButtons] = useState<{ [key: number]: boolean }>({});
|
||||||
|
|
||||||
|
const handleRatingClick = (rating: number) => {
|
||||||
|
console.log("rating clicked");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseEnter = (buttonIndex: number) => {
|
||||||
|
setHoveredButtons((prev) => ({ ...prev, [buttonIndex]: true }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseLeave = (buttonIndex: number) => {
|
||||||
|
setHoveredButtons((prev) => ({ ...prev, [buttonIndex]: false }));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx("rating-bubble")} title="Click to Copy Notification Message">
|
||||||
|
<Button
|
||||||
|
className="close-btn ghost grey vertical-padding-10"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
onRemove(id);
|
||||||
|
}}
|
||||||
|
aria-label="Close"
|
||||||
|
>
|
||||||
|
<i className={clsx(makeIconClass("close", false))}></i>
|
||||||
|
</Button>
|
||||||
|
<div className="notification-inner">
|
||||||
|
<div className="notification-text">
|
||||||
|
{title && <div className={clsx("notification-title green")}>{title}</div>}
|
||||||
|
{message && <div className="notification-message">{message}</div>}
|
||||||
|
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((rating) => (
|
||||||
|
<Button
|
||||||
|
key={rating}
|
||||||
|
className={clsx(hoveredButtons[rating] ? "green" : "grey")}
|
||||||
|
onClick={() => handleRatingClick(rating)}
|
||||||
|
onMouseEnter={() => handleMouseEnter(rating)}
|
||||||
|
onMouseLeave={() => handleMouseLeave(rating)}
|
||||||
|
>
|
||||||
|
{rating}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { RatingBubble };
|
3
frontend/types/custom.d.ts
vendored
3
frontend/types/custom.d.ts
vendored
@ -320,7 +320,8 @@ declare global {
|
|||||||
hidden?: boolean;
|
hidden?: boolean;
|
||||||
actions?: NotificationActionType[];
|
actions?: NotificationActionType[];
|
||||||
persistent?: boolean;
|
persistent?: boolean;
|
||||||
type?: "error" | "update" | "info" | "warning";
|
componentType?: "rating";
|
||||||
|
statusType?: "error" | "update" | "info" | "warning";
|
||||||
};
|
};
|
||||||
|
|
||||||
interface AbstractWshClient {
|
interface AbstractWshClient {
|
||||||
|
Loading…
Reference in New Issue
Block a user