mirror of
https://github.com/lukevella/rallly.git
synced 2025-05-21 21:06:20 +02:00
🚧 Add more info about giving feedback in the open beta environment (#508)
This commit is contained in:
parent
9586a072d4
commit
ce3e5540db
7 changed files with 122 additions and 69 deletions
|
@ -8,6 +8,7 @@ import {
|
||||||
} from "@floating-ui/react-dom-interactions";
|
} from "@floating-ui/react-dom-interactions";
|
||||||
import { Menu } from "@headlessui/react";
|
import { Menu } from "@headlessui/react";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
import Link from "next/link";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import { transformOriginByPlacement } from "@/utils/constants";
|
import { transformOriginByPlacement } from "@/utils/constants";
|
||||||
|
@ -82,30 +83,25 @@ export const DropdownItem: React.VoidFunctionComponent<{
|
||||||
href?: string;
|
href?: string;
|
||||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||||
}> = ({ icon: Icon, label, onClick, disabled, href }) => {
|
}> = ({ icon: Icon, label, onClick, disabled, href }) => {
|
||||||
const Element = href ? "a" : "button";
|
const Element = href ? Link : "button";
|
||||||
return (
|
return (
|
||||||
<Menu.Item disabled={disabled}>
|
<Menu.Item disabled={disabled}>
|
||||||
{({ active }) => (
|
{({ active }) => (
|
||||||
<Element
|
<Element
|
||||||
href={href}
|
// TODO (Luke Vella) [2023-02-10]: Find a better solution for having a mixture of links and buttons
|
||||||
|
// in a dropdown
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
href={href as any}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"group flex w-full items-center rounded py-2 pl-2 pr-4",
|
"relative flex w-full select-none items-center whitespace-nowrap rounded py-1.5 pl-2 pr-4 font-medium text-slate-600",
|
||||||
{
|
{
|
||||||
"bg-primary-500 text-white": active,
|
"bg-slate-100": active,
|
||||||
"text-gray-700": !active,
|
|
||||||
"opacity-50": disabled,
|
"opacity-50": disabled,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{Icon && (
|
{Icon && <Icon className={clsx("mr-2 h-5 shrink-0")} />}
|
||||||
<Icon
|
|
||||||
className={clsx("mr-2 h-5 w-5", {
|
|
||||||
"text-white": active,
|
|
||||||
"text-primary-500": !active,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{label}
|
{label}
|
||||||
</Element>
|
</Element>
|
||||||
)}
|
)}
|
||||||
|
|
3
src/components/icons/beaker.svg
Normal file
3
src/components/icons/beaker.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 458 B |
|
@ -1,11 +1,11 @@
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { AnimatePresence } from "framer-motion";
|
import { AnimatePresence } from "framer-motion";
|
||||||
import Link from "next/link";
|
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { LoginLink } from "@/components/auth/login-modal";
|
import { LoginLink } from "@/components/auth/login-modal";
|
||||||
import Adjustments from "@/components/icons/adjustments.svg";
|
import Adjustments from "@/components/icons/adjustments.svg";
|
||||||
|
import Beaker from "@/components/icons/beaker.svg";
|
||||||
import Home from "@/components/icons/home.svg";
|
import Home from "@/components/icons/home.svg";
|
||||||
import Login from "@/components/icons/login.svg";
|
import Login from "@/components/icons/login.svg";
|
||||||
import Menu from "@/components/icons/menu.svg";
|
import Menu from "@/components/icons/menu.svg";
|
||||||
|
@ -16,7 +16,10 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/popover";
|
||||||
import Preferences from "@/components/preferences";
|
import Preferences from "@/components/preferences";
|
||||||
import { useUser } from "@/components/user-provider";
|
import { useUser } from "@/components/user-provider";
|
||||||
|
|
||||||
|
import Dropdown, { DropdownItem } from "../../dropdown";
|
||||||
import { Logo } from "../../logo";
|
import { Logo } from "../../logo";
|
||||||
|
import { useModalContext } from "../../modal/modal-provider";
|
||||||
|
import OpenBeta from "../../open-beta-modal";
|
||||||
import { UserDropdown } from "./user-dropdown";
|
import { UserDropdown } from "./user-dropdown";
|
||||||
|
|
||||||
export const MobileNavigation = (props: { className?: string }) => {
|
export const MobileNavigation = (props: { className?: string }) => {
|
||||||
|
@ -24,6 +27,7 @@ export const MobileNavigation = (props: { className?: string }) => {
|
||||||
const { t } = useTranslation(["common", "app"]);
|
const { t } = useTranslation(["common", "app"]);
|
||||||
|
|
||||||
const [isPinned, setIsPinned] = React.useState(false);
|
const [isPinned, setIsPinned] = React.useState(false);
|
||||||
|
const modalContext = useModalContext();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const scrollHandler = () => {
|
const scrollHandler = () => {
|
||||||
|
@ -51,8 +55,9 @@ export const MobileNavigation = (props: { className?: string }) => {
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Popover>
|
<Dropdown
|
||||||
<PopoverTrigger asChild={true}>
|
placement="bottom-start"
|
||||||
|
trigger={
|
||||||
<button
|
<button
|
||||||
role="button"
|
role="button"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -61,11 +66,33 @@ export const MobileNavigation = (props: { className?: string }) => {
|
||||||
<Menu className="mr-2 w-5 group-hover:text-primary-500" />
|
<Menu className="mr-2 w-5 group-hover:text-primary-500" />
|
||||||
<Logo />
|
<Logo />
|
||||||
</button>
|
</button>
|
||||||
</PopoverTrigger>
|
}
|
||||||
<PopoverContent align="start">
|
>
|
||||||
<AppMenu />
|
<DropdownItem href="/" label={t("home")} icon={Home} />
|
||||||
</PopoverContent>
|
<DropdownItem href="/new" label={t("app:createNew")} icon={Pencil} />
|
||||||
</Popover>
|
<DropdownItem
|
||||||
|
href="https://support.rallly.co"
|
||||||
|
label={t("support")}
|
||||||
|
icon={Support}
|
||||||
|
/>
|
||||||
|
{process.env.NEXT_PUBLIC_BETA === "1" ? (
|
||||||
|
<>
|
||||||
|
<DropdownItem
|
||||||
|
onClick={() => {
|
||||||
|
// open modal
|
||||||
|
modalContext.render({
|
||||||
|
content: <OpenBeta />,
|
||||||
|
footer: null,
|
||||||
|
showClose: true,
|
||||||
|
overlayClosable: true,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
label="Feedback"
|
||||||
|
icon={Beaker}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{user ? null : (
|
{user ? null : (
|
||||||
|
@ -121,36 +148,3 @@ export const MobileNavigation = (props: { className?: string }) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AppMenu: React.VoidFunctionComponent<{ className?: string }> = ({
|
|
||||||
className,
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation(["common", "app"]);
|
|
||||||
return (
|
|
||||||
<div className={clsx("space-y-1", className)}>
|
|
||||||
<Link
|
|
||||||
href="/"
|
|
||||||
className="flex cursor-pointer items-center space-x-2 whitespace-nowrap rounded px-2 py-1 pr-4 font-medium text-slate-600 transition-colors hover:bg-slate-50 hover:text-slate-600 hover:no-underline active:bg-gray-300"
|
|
||||||
>
|
|
||||||
<Home className="h-5 opacity-75 " />
|
|
||||||
<span className="inline-block">{t("app:home")}</span>
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href="/new"
|
|
||||||
className="flex cursor-pointer items-center space-x-2 whitespace-nowrap rounded px-2 py-1 pr-4 font-medium text-slate-600 transition-colors hover:bg-slate-50 hover:text-slate-600 hover:no-underline active:bg-gray-300"
|
|
||||||
>
|
|
||||||
<Pencil className="h-5 opacity-75 " />
|
|
||||||
<span className="inline-block">{t("app:createNew")}</span>
|
|
||||||
</Link>
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
href="https://support.rallly.co"
|
|
||||||
className="flex cursor-pointer items-center space-x-2 whitespace-nowrap rounded px-2 py-1 pr-4 font-medium text-slate-600 transition-colors hover:bg-slate-50 hover:text-slate-600 hover:no-underline active:bg-gray-300"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
<Support className="h-5 opacity-75" />
|
|
||||||
<span className="inline-block">{t("common:support")}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import clsx from "clsx";
|
||||||
export const Logo = (props: { className?: string; color?: boolean }) => {
|
export const Logo = (props: { className?: string; color?: boolean }) => {
|
||||||
const { color = true } = props;
|
const { color = true } = props;
|
||||||
return (
|
return (
|
||||||
<span className="inline-flex items-center">
|
<span className="inline-flex select-none items-center">
|
||||||
<span
|
<span
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"font-semibold uppercase tracking-widest",
|
"font-semibold uppercase tracking-widest",
|
||||||
|
@ -16,7 +16,7 @@ export const Logo = (props: { className?: string; color?: boolean }) => {
|
||||||
Rallly
|
Rallly
|
||||||
</span>
|
</span>
|
||||||
{process.env.NEXT_PUBLIC_BETA === "1" ? (
|
{process.env.NEXT_PUBLIC_BETA === "1" ? (
|
||||||
<span className="ml-2 inline-block animate-pulse rounded bg-rose-500 px-1 text-xs lowercase tracking-tight text-white">
|
<span className="ml-2 inline-block rounded bg-rose-500 px-1 text-xs lowercase tracking-tight text-slate-50">
|
||||||
beta
|
beta
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -64,7 +64,7 @@ const Modal: React.VoidFunctionComponent<ModalProps> = ({
|
||||||
initial={{ opacity: 0, scale: 0.9 }}
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
exit={{ opacity: 0, scale: 0.9 }}
|
exit={{ opacity: 0, scale: 0.9 }}
|
||||||
className="relative z-50 my-8 inline-block max-w-full transform text-left align-middle"
|
className="relative z-50 m-3 inline-block max-w-full transform text-left align-middle sm:m-8"
|
||||||
>
|
>
|
||||||
<div className="max-w-full overflow-hidden rounded-md bg-white shadow-huge">
|
<div className="max-w-full overflow-hidden rounded-md bg-white shadow-huge">
|
||||||
{showClose ? (
|
{showClose ? (
|
||||||
|
|
71
src/components/open-beta-modal.tsx
Normal file
71
src/components/open-beta-modal.tsx
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
import { Logo } from "./logo";
|
||||||
|
|
||||||
|
const OpenBeta = () => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="bg-pattern border-b px-4 py-8 text-center text-2xl">
|
||||||
|
<Logo />
|
||||||
|
</div>
|
||||||
|
<div className="max-w-3xl p-3 sm:p-6">
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
The open beta allows you to test out new features before they are
|
||||||
|
officially released to the general public. By participating you,
|
||||||
|
will have the opportunity to provide feedback and help shape the
|
||||||
|
future of Rallly!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Feedback</h2>
|
||||||
|
<p></p>
|
||||||
|
<ul className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
|
<a
|
||||||
|
href="https://github.com/lukevella/rallly/issues/new?assignees=&labels=bug&template=---bug-report.md&title="
|
||||||
|
className="rounded border p-3 hover:text-primary-500"
|
||||||
|
>
|
||||||
|
🐞 Submit a bug report
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://github.com/lukevella/rallly/discussions/new/choose"
|
||||||
|
className="rounded border p-3 hover:text-primary-500"
|
||||||
|
>
|
||||||
|
📢 Open a discussion with the community
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://discord.gg/uzg4ZcHbuM"
|
||||||
|
className="rounded border p-3 hover:text-primary-500"
|
||||||
|
>
|
||||||
|
💬 Chat on Discord
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="mailto:feedback@rallly.co"
|
||||||
|
className="rounded border p-3 hover:text-primary-500"
|
||||||
|
>
|
||||||
|
✉️ Send an email
|
||||||
|
</a>
|
||||||
|
</ul>
|
||||||
|
<div className="bg-patte mt-4 rounded border bg-slate-50 p-4">
|
||||||
|
<h2 className="text-slate-800">Important</h2>
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
You should not rely on the beta for any important data or
|
||||||
|
information.
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The beta should be used exclusively for testing purposes.
|
||||||
|
Features, polls, accounts, or data may be removed at any time
|
||||||
|
without prior notice.
|
||||||
|
</p>
|
||||||
|
<p className="m-0">
|
||||||
|
Any data or information saved on the beta website cannot be
|
||||||
|
accessed on the production website and vice versa.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OpenBeta;
|
|
@ -4,7 +4,6 @@ import "~/style.css";
|
||||||
|
|
||||||
import { Inter, Noto_Sans_Mono } from "@next/font/google";
|
import { Inter, Noto_Sans_Mono } from "@next/font/google";
|
||||||
import { inject } from "@vercel/analytics";
|
import { inject } from "@vercel/analytics";
|
||||||
import { domAnimation, LazyMotion, m } from "framer-motion";
|
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import { AppProps } from "next/app";
|
import { AppProps } from "next/app";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
|
@ -89,17 +88,7 @@ const MyApp: NextPage<AppPropsWithLayout> = ({ Component, pageProps }) => {
|
||||||
--font-noto: ${noto.style.fontFamily};
|
--font-noto: ${noto.style.fontFamily};
|
||||||
}
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
<LazyMotion features={domAnimation}>
|
{getLayout(<Component {...pageProps} />)}
|
||||||
{getLayout(
|
|
||||||
<m.div
|
|
||||||
initial={{ opacity: 0, y: -50 }}
|
|
||||||
animate={{ opacity: 1, y: 0 }}
|
|
||||||
exit={{ opacity: 0, y: 50 }}
|
|
||||||
>
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</m.div>,
|
|
||||||
)}
|
|
||||||
</LazyMotion>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue