feat: public boards
This commit is contained in:
@@ -21,7 +21,9 @@ interface CheckboxDropdownProps {
|
||||
items?: Item[];
|
||||
groups?: Group[];
|
||||
menuSpacing?: "sm" | "md" | "lg";
|
||||
position?: "left" | "right";
|
||||
handleSelect: (groupKey: string | null, item: { key: string }) => void;
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
export default function CheckboxDropdown({
|
||||
@@ -29,7 +31,9 @@ export default function CheckboxDropdown({
|
||||
items,
|
||||
groups,
|
||||
menuSpacing = "sm",
|
||||
position = "left",
|
||||
handleSelect,
|
||||
asChild = true,
|
||||
}: CheckboxDropdownProps) {
|
||||
const [selectedGroup, setSelectedGroup] = useState<string | null>(null);
|
||||
|
||||
@@ -45,7 +49,10 @@ export default function CheckboxDropdown({
|
||||
className="relative flex w-full flex-wrap items-center text-left"
|
||||
>
|
||||
<>
|
||||
<Menu.Button className="focus-visible:outline-none">
|
||||
<Menu.Button
|
||||
as={asChild ? "div" : undefined}
|
||||
className="focus-visible:outline-none"
|
||||
>
|
||||
{children}
|
||||
</Menu.Button>
|
||||
|
||||
@@ -61,7 +68,8 @@ export default function CheckboxDropdown({
|
||||
>
|
||||
<Menu.Items
|
||||
className={twMerge(
|
||||
"absolute left-0 z-50 mt-2 w-56 origin-top-left rounded-md border-[1px] border-light-200 bg-light-50 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-dark-500 dark:bg-dark-200",
|
||||
"absolute z-50 mt-2 w-56 origin-top-left rounded-md border-[1px] border-light-200 bg-light-50 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-dark-500 dark:bg-dark-200",
|
||||
position === "left" ? "left-0" : "right-0",
|
||||
menuSpacingClass[menuSpacing],
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -21,8 +21,14 @@ export function NewWorkspaceForm() {
|
||||
|
||||
const createWorkspace = api.workspace.create.useMutation({
|
||||
onSuccess: (values) => {
|
||||
if (values?.publicId && values.name) {
|
||||
switchWorkspace({ publicId: values.publicId, name: values.name });
|
||||
if (values.publicId && values.name) {
|
||||
switchWorkspace({
|
||||
publicId: values.publicId,
|
||||
name: values.name,
|
||||
// description: values.description,
|
||||
// slug: values.slug,
|
||||
// plan: values.plan,
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
},
|
||||
@@ -30,13 +36,14 @@ export function NewWorkspaceForm() {
|
||||
showPopup({
|
||||
header: "Unable to create workspace",
|
||||
message: "Please try again later, or contact customer support.",
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const nameElement: HTMLElement | null =
|
||||
document?.querySelector<HTMLElement>("#workspace-name");
|
||||
document.querySelector<HTMLElement>("#workspace-name");
|
||||
if (nameElement) nameElement.focus();
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { useEffect } from "react";
|
||||
import { HiOutlineExclamationCircle, HiXMark } from "react-icons/hi2";
|
||||
import {
|
||||
HiOutlineCheckCircle,
|
||||
HiOutlineExclamationCircle,
|
||||
HiXMark,
|
||||
} from "react-icons/hi2";
|
||||
|
||||
import { usePopup } from "~/providers/popup";
|
||||
|
||||
const Popup: React.FC = () => {
|
||||
const { isOpen, popupHeader, popupMessage, hidePopup } = usePopup();
|
||||
const { isOpen, popupHeader, popupMessage, popupIcon, hidePopup } =
|
||||
usePopup();
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
@@ -20,7 +25,7 @@ const Popup: React.FC = () => {
|
||||
return (
|
||||
<div
|
||||
aria-live="assertive"
|
||||
className="pointer-events-none fixed inset-0 z-10 flex items-end px-4 py-6 sm:items-end sm:p-6"
|
||||
className="pointer-events-none fixed inset-0 z-10 flex items-end p-3 sm:items-end"
|
||||
>
|
||||
<div className="flex w-full flex-col items-center space-y-4 sm:items-end">
|
||||
<Transition
|
||||
@@ -36,10 +41,18 @@ const Popup: React.FC = () => {
|
||||
<div className="p-4">
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0">
|
||||
<HiOutlineExclamationCircle
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-red-400"
|
||||
/>
|
||||
{popupIcon === "success" && (
|
||||
<HiOutlineCheckCircle
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-green-400"
|
||||
/>
|
||||
)}
|
||||
{popupIcon === "error" && (
|
||||
<HiOutlineExclamationCircle
|
||||
aria-hidden="true"
|
||||
className="h-6 w-6 text-red-400"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="ml-3 w-0 flex-1 pt-0.5">
|
||||
<p className="text-sm font-medium text-neutral-900 dark:text-dark-1000">
|
||||
|
||||
27
apps/web/src/components/ThemeToggle.tsx
Normal file
27
apps/web/src/components/ThemeToggle.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { CgDarkMode } from "react-icons/cg";
|
||||
|
||||
import { useTheme } from "~/providers/theme";
|
||||
|
||||
const ThemeToggle = () => {
|
||||
const { themePreference, switchTheme } = useTheme();
|
||||
|
||||
const toggleTheme = () => {
|
||||
switchTheme(themePreference === "light" ? "dark" : "light");
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="rounded p-1.5 transition-all hover:bg-light-200 dark:hover:bg-dark-100"
|
||||
aria-label={`Switch to ${themePreference === "light" ? "dark" : "light"} theme`}
|
||||
>
|
||||
<CgDarkMode
|
||||
className={`h-4 w-4 text-light-900 transition-transform duration-200 dark:text-dark-900 ${
|
||||
themePreference === "dark" ? "rotate-180" : "rotate-0"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemeToggle;
|
||||
Reference in New Issue
Block a user