RTL (right-to-left) layout (#1654)

* added rtl to body

* added locale checkker in _document.tsx to check for ar or he locale

* added rtl modifiers for event-types

* added rtl classes

* wip

* wip

Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
This commit is contained in:
Peer Richelsen 2022-02-01 22:17:37 +00:00 committed by GitHub
parent d9bb8aacfc
commit 8bb3e9c0be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 203 additions and 164 deletions

View file

@ -29,12 +29,12 @@ export default function AddToHomescreen() {
<path d="M35 40H15c-1.7 0-3-1.3-3-3V19c0-1.7 1.3-3 3-3h7v2h-7c-.6 0-1 .4-1 1v18c0 .6.4 1 1 1h20c.6 0 1-.4 1-1V19c0-.6-.4-1-1-1h-7v-2h7c1.7 0 3 1.3 3 3v18c0 1.7-1.3 3-3 3z" />
</svg>
</span>
<p className="ml-3 text-xs font-medium text-white">
<p className="text-xs font-medium text-white ltr:ml-3 rtl:mr-3">
<span className="inline">{t("add_to_homescreen")}</span>
</p>
</div>
<div className="flex-shrink-0 order-2 sm:order-3 sm:ml-2">
<div className="flex-shrink-0 order-2 sm:order-3">
<button
onClick={() => setCloseBanner(true)}
type="button"

View file

@ -43,7 +43,7 @@ export function DialogHeader(props: DialogHeaderProps) {
export function DialogFooter(props: { children: ReactNode }) {
return (
<div>
<div className="flex justify-end mt-5 space-x-2">{props.children}</div>
<div className="flex justify-end mt-5 rtl:space-x-reverse space-x-2">{props.children}</div>
</div>
);
}

View file

@ -17,7 +17,7 @@ const NavTabs: FC<Props> = ({ tabs, linkProps }) => {
const router = useRouter();
return (
<>
<nav className="flex -mb-px space-x-2 sm:space-x-5" aria-label="Tabs">
<nav className="-mb-px flex rtl:space-x-reverse space-x-2 sm:rtl:space-x-reverse space-x-5" aria-label="Tabs">
{tabs.map((tab) => {
const isCurrent = router.asPath === tab.href;
return (
@ -34,7 +34,7 @@ const NavTabs: FC<Props> = ({ tabs, linkProps }) => {
<tab.icon
className={classNames(
isCurrent ? "text-neutral-900" : "text-gray-400 group-hover:text-gray-500",
"-ml-0.5 mr-2 h-5 w-5 hidden sm:inline-block"
"-ml-0.5 ltr:mr-2 rtl:ml-2 h-5 w-5 hidden sm:inline-block"
)}
aria-hidden="true"
/>

View file

@ -106,10 +106,10 @@ export function ShellSubHeading(props: {
return (
<div className={classNames("block sm:flex justify-between mb-3", props.className)}>
<div>
<h2 className="flex items-center content-center space-x-2 text-base font-bold leading-6 text-gray-900">
<h2 className="flex items-center content-center rtl:space-x-reverse space-x-2 text-base font-bold leading-6 text-gray-900">
{props.title}
</h2>
{props.subtitle && <p className="mr-4 text-sm text-neutral-500">{props.subtitle}</p>}
{props.subtitle && <p className="ltr:mr-4 text-sm text-neutral-500">{props.subtitle}</p>}
</div>
{props.actions && <div className="flex-shrink-0">{props.actions}</div>}
</div>
@ -235,7 +235,7 @@ export default function Shell(props: {
item.current
? "text-neutral-500"
: "text-neutral-400 group-hover:text-neutral-500",
"mr-3 flex-shrink-0 h-5 w-5"
"ltr:mr-3 rtl:ml-3 flex-shrink-0 h-5 w-5"
)}
aria-hidden="true"
/>
@ -300,12 +300,12 @@ export default function Shell(props: {
</div>
)}
<div className="block sm:flex justify-between px-4 sm:px-6 md:px-8 min-h-[80px]">
{props.HeadingLeftIcon && <div className="mr-4">{props.HeadingLeftIcon}</div>}
{props.HeadingLeftIcon && <div className="ltr:mr-4">{props.HeadingLeftIcon}</div>}
<div className="w-full mb-8">
<h1 className="mb-1 text-xl font-bold tracking-wide text-gray-900 font-cal">
{props.heading}
</h1>
<p className="mr-4 text-sm text-neutral-500">{props.subtitle}</p>
<p className="text-sm ltr:mr-4 rtl:ml-4 text-neutral-500">{props.subtitle}</p>
</div>
<div className="flex-shrink-0 mb-4">{props.CTA}</div>
</div>
@ -370,11 +370,11 @@ function UserDropdown({ small }: { small?: boolean }) {
return (
<Dropdown>
<DropdownMenuTrigger asChild>
<div className="flex items-center w-full space-x-2 cursor-pointer group appearance-none">
<div className="flex items-center w-full appearance-none cursor-pointer group">
<span
className={classNames(
small ? "w-8 h-8" : "w-10 h-10",
"bg-gray-300 rounded-full flex-shrink-0 relative"
"bg-gray-300 rounded-full flex-shrink-0 relative ltr:mr-3 rtl:ml-3"
)}>
<img
className="rounded-full"
@ -424,7 +424,7 @@ function UserDropdown({ small }: { small?: boolean }) {
user?.away
? "text-purple-500 group-hover:text-purple-700"
: "text-gray-500 group-hover:text-gray-700",
"mr-2 flex-shrink-0 h-5 w-5"
"ltr:mr-3 rtl:ml-3 flex-shrink-0 h-5 w-5"
)}
aria-hidden="true"
/>
@ -439,7 +439,7 @@ function UserDropdown({ small }: { small?: boolean }) {
rel="noopener noreferrer"
href={`${process.env.NEXT_PUBLIC_APP_URL}/${user.username}`}
className="flex items-center px-4 py-2 text-sm text-gray-700">
<ExternalLinkIcon className="w-5 h-5 mr-3 text-gray-500" /> {t("view_public_page")}
<ExternalLinkIcon className="w-5 h-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("view_public_page")}
</a>
</DropdownMenuItem>
)}
@ -454,22 +454,22 @@ function UserDropdown({ small }: { small?: boolean }) {
viewBox="0 0 2447.6 2452.5"
className={classNames(
"text-gray-500 group-hover:text-gray-700",
"mt-0.5 mr-3 flex-shrink-0 h-4 w-4"
"mt-0.5 ltr:mr-2 rtl:ml-2 flex-shrink-0 h-4 w-4"
)}
xmlns="http://www.w3.org/2000/svg">
<g clipRule="evenodd" fillRule="evenodd">
<path
d="m897.4 0c-135.3.1-244.8 109.9-244.7 245.2-.1 135.3 109.5 245.1 244.8 245.2h244.8v-245.1c.1-135.3-109.5-245.1-244.9-245.3.1 0 .1 0 0 0m0 654h-652.6c-135.3.1-244.9 109.9-244.8 245.2-.2 135.3 109.4 245.1 244.7 245.3h652.7c135.3-.1 244.9-109.9 244.8-245.2.1-135.4-109.5-245.2-244.8-245.3z"
fill="#9BA6B6"></path>
fill="currentColor"></path>
<path
d="m2447.6 899.2c.1-135.3-109.5-245.1-244.8-245.2-135.3.1-244.9 109.9-244.8 245.2v245.3h244.8c135.3-.1 244.9-109.9 244.8-245.3zm-652.7 0v-654c.1-135.2-109.4-245-244.7-245.2-135.3.1-244.9 109.9-244.8 245.2v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.3z"
fill="#9BA6B6"></path>
fill="currentColor"></path>
<path
d="m1550.1 2452.5c135.3-.1 244.9-109.9 244.8-245.2.1-135.3-109.5-245.1-244.8-245.2h-244.8v245.2c-.1 135.2 109.5 245 244.8 245.2zm0-654.1h652.7c135.3-.1 244.9-109.9 244.8-245.2.2-135.3-109.4-245.1-244.7-245.3h-652.7c-135.3.1-244.9 109.9-244.8 245.2-.1 135.4 109.4 245.2 244.7 245.3z"
fill="#9BA6B6"></path>
fill="currentColor"></path>
<path
d="m0 1553.2c-.1 135.3 109.5 245.1 244.8 245.2 135.3-.1 244.9-109.9 244.8-245.2v-245.2h-244.8c-135.3.1-244.9 109.9-244.8 245.2zm652.7 0v654c-.2 135.3 109.4 245.1 244.7 245.3 135.3-.1 244.9-109.9 244.8-245.2v-653.9c.2-135.3-109.4-245.1-244.7-245.3-135.4 0-244.9 109.8-244.8 245.1 0 0 0 .1 0 0"
fill="#9BA6B6"></path>
fill="currentColor"></path>
</g>
</svg>
{t("join_our_slack")}
@ -481,7 +481,7 @@ function UserDropdown({ small }: { small?: boolean }) {
rel="noopener noreferrer"
href="https://cal.com/roadmap"
className="flex items-center px-4 py-2 text-sm text-gray-700">
<MapIcon className="w-5 h-5 mr-3 text-gray-500" /> {t("visit_roadmap")}
<MapIcon className="w-5 h-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("visit_roadmap")}
</a>
</DropdownMenuItem>
<HelpMenuItemDynamic />
@ -491,7 +491,10 @@ function UserDropdown({ small }: { small?: boolean }) {
onClick={() => signOut({ callbackUrl: "/auth/logout" })}
className="flex px-4 py-2 text-sm cursor-pointer hover:bg-gray-100 hover:text-gray-900">
<LogoutIcon
className={classNames("text-gray-500 group-hover:text-gray-700", "mr-2 flex-shrink-0 h-5 w-5")}
className={classNames(
"text-gray-500 group-hover:text-gray-700",
"ltr:mr-3 rtl:ml-3 flex-shrink-0 h-5 w-5"
)}
aria-hidden="true"
/>
{t("sign_out")}

View file

@ -119,7 +119,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
<div className="flex-shrink-0">
<ExclamationIcon className="w-5 h-5 text-yellow-400" aria-hidden="true" />
</div>
<div className="ml-3">
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm text-yellow-700">{t("slots_load_fail")}</p>
</div>
</div>

View file

@ -74,16 +74,20 @@ function BookingListItem(booking: BookingItem) {
return (
<tr className="flex">
<td className="hidden py-4 pl-6 align-top sm:table-cell whitespace-nowrap">
<td className="hidden py-4 align-top ltr:pl-6 rtl:pr-6 sm:table-cell whitespace-nowrap">
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
<div className="text-sm text-gray-500">
{dayjs(booking.startTime).format("HH:mm")} - {dayjs(booking.endTime).format("HH:mm")}
</div>
</td>
<td className={"pl-4 py-4 flex-1" + (booking.rejected ? " line-through" : "")}>
<td className={"ltr:pl-4 rtl:pr-4 py-4 flex-1" + (booking.rejected ? " line-through" : "")}>
<div className="sm:hidden">
{!booking.confirmed && !booking.rejected && <Tag className="mb-2 mr-2">{t("unconfirmed")}</Tag>}
{!!booking?.eventType?.price && !booking.paid && <Tag className="mb-2 mr-2">Pending payment</Tag>}
{!booking.confirmed && !booking.rejected && (
<Tag className="mb-2 ltr:mr-2 rtl:ml-2">{t("unconfirmed")}</Tag>
)}
{!!booking?.eventType?.price && !booking.paid && (
<Tag className="mb-2 ltr:mr-2 rtl:ml-2">Pending payment</Tag>
)}
<div className="text-sm font-medium text-gray-900">
{startTime}:{" "}
<small className="text-sm text-gray-500">
@ -97,10 +101,10 @@ function BookingListItem(booking: BookingItem) {
{booking.eventType?.team && <strong>{booking.eventType.team.name}: </strong>}
{booking.title}
{!!booking?.eventType?.price && !booking.paid && (
<Tag className="hidden ml-2 sm:inline-flex">Pending payment</Tag>
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">Pending payment</Tag>
)}
{!booking.confirmed && !booking.rejected && (
<Tag className="hidden ml-2 sm:inline-flex">{t("unconfirmed")}</Tag>
<Tag className="hidden ltr:ml-2 rtl:mr-2 sm:inline-flex">{t("unconfirmed")}</Tag>
)}
</div>
{booking.description && (
@ -115,7 +119,7 @@ function BookingListItem(booking: BookingItem) {
)}
</td>
<td className="py-4 pr-4 text-sm font-medium text-right whitespace-nowrap">
<td className="py-4 text-sm font-medium text-right ltr:pr-4 rtl:pl-4 whitespace-nowrap">
{isUpcoming && !isCancelled ? (
<>
{!booking.confirmed && !booking.rejected && <TableActions actions={pendingActions} />}

View file

@ -174,7 +174,10 @@ function DatePicker({
<div className="w-1/2 text-right text-gray-600 dark:text-gray-400">
<button
onClick={decrementMonth}
className={classNames("group mr-2 p-1", isFirstMonth && "text-gray-400 dark:text-gray-600")}
className={classNames(
"group ltr:mr-2 rtl:ml-2 p-1",
isFirstMonth && "text-gray-400 dark:text-gray-600"
)}
disabled={isFirstMonth}
data-testid="decrementMonth">
<ChevronLeftIcon className="w-5 h-5 group-hover:text-black dark:group-hover:text-white" />

View file

@ -40,7 +40,7 @@ const TimeOptions: FC<Props> = (props) => {
<div className="w-1/2 font-medium text-gray-600 dark:text-white">{t("time_options")}</div>
<div className="w-1/2">
<Switch.Group as="div" className="flex items-center justify-end">
<Switch.Label as="span" className="mr-3">
<Switch.Label as="span" className="ltr:mr-3">
<span className="text-sm text-gray-500 dark:text-white">{t("am_pm")}</span>
</Switch.Label>
<Switch
@ -59,7 +59,7 @@ const TimeOptions: FC<Props> = (props) => {
)}
/>
</Switch>
<Switch.Label as="span" className="ml-3">
<Switch.Label as="span" className="ltr:ml-3 rtl:mr-3">
<span className="text-sm text-gray-500 dark:text-white">{t("24_h")}</span>
</Switch.Label>
</Switch.Group>

View file

@ -134,7 +134,7 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
size={9}
truncateAfter={5}
/>
<div className="ml-3">
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm font-medium text-black dark:text-gray-300">{profile.name}</p>
<div className="flex gap-2 text-xs font-medium text-gray-600">
{eventType.title}

View file

@ -389,12 +389,12 @@ const BookingPage = (props: BookingPageProps) => {
<label key={i} className="block">
<input
type="radio"
className="w-4 h-4 mr-2 text-black border-gray-300 location focus:ring-black"
className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-black border-gray-300 location focus:ring-black"
{...bookingForm.register("locationType", { required: true })}
value={location.type}
defaultChecked={selectedLocation === location.type}
/>
<span className="ml-2 text-sm dark:text-gray-500">
<span className="ltr:ml-2 rtl:mr-2text-sm dark:text-gray-500">
{locationLabels[location.type]}
</span>
</label>
@ -465,7 +465,7 @@ const BookingPage = (props: BookingPageProps) => {
required: input.required,
})}
id={"custom_" + input.id}
className="w-4 h-4 mr-2 text-black border-gray-300 rounded focus:ring-black"
className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-black border-gray-300 rounded focus:ring-black"
placeholder=""
/>
<label
@ -539,7 +539,7 @@ const BookingPage = (props: BookingPageProps) => {
placeholder={t("share_additional_notes")}
/>
</div>
<div className="flex items-start space-x-2">
<div className="flex items-start rtl:space-x-reverse space-x-2">
<Button type="submit" loading={mutation.isLoading}>
{rescheduleUid ? t("reschedule") : t("confirm")}
</Button>
@ -554,7 +554,7 @@ const BookingPage = (props: BookingPageProps) => {
<div className="flex-shrink-0">
<ExclamationIcon className="w-5 h-5 text-yellow-400" aria-hidden="true" />
</div>
<div className="ml-3">
<div className="ltr:ml-3 rtl:mr-3">
<p className="text-sm text-yellow-700">
{rescheduleUid ? t("reschedule_fail") : t("booking_fail")}
</p>

View file

@ -33,7 +33,7 @@ export default function ConfirmationDialogContent(props: PropsWithChildren<Confi
<DialogContent>
<div className="flex">
{variety && (
<div className="mr-3 mt-0.5">
<div className="ltr:mr-3 mt-0.5">
{variety === "danger" && (
<div className="p-2 mx-auto text-center bg-red-100 rounded-full">
<ExclamationIcon className="w-5 h-5 text-red-600" />

View file

@ -141,7 +141,12 @@ export default function CreateEventTypeButton(props: Props) {
key={option.slug}
className="px-3 py-2 cursor-pointer hover:bg-neutral-100 focus:outline-none"
onSelect={() => openModal(option)}>
<Avatar alt={option.name || ""} imageSrc={option.image} size={6} className="inline mr-2" />
<Avatar
alt={option.name || ""}
imageSrc={option.image}
size={6}
className="inline ltr:mr-2 rtl:ml-2"
/>
{option.name ? option.name : option.slug}
</DropdownMenuItem>
))}
@ -222,7 +227,7 @@ export default function CreateEventTypeButton(props: Props) {
<RadioArea.Group
{...register("schedulingType")}
onChange={(val) => form.setValue("schedulingType", val as SchedulingType)}
className="relative flex mt-1 space-x-6 rounded-sm shadow-sm">
className="relative flex mt-1 rtl:space-x-reverse space-x-6 rounded-sm shadow-sm">
<RadioArea.Item value={SchedulingType.COLLECTIVE} className="w-1/2 text-sm">
<strong className="block mb-1">{t("collective")}</strong>
<p>{t("collective_description")}</p>

View file

@ -37,7 +37,7 @@ export const EventTypeDescription = ({ eventType, className }: EventTypeDescript
{eventType.description.length > 100 && "..."}
</h2>
)}
<ul className="flex mt-2 space-x-4 ">
<ul className="flex mt-2 rtl:space-x-reverse space-x-4 ">
<li className="flex whitespace-nowrap">
<ClockIcon className="inline mt-0.5 mr-1.5 h-4 w-4 text-neutral-400" aria-hidden="true" />
{eventType.length}m

View file

@ -14,7 +14,7 @@ function IntegrationListItem(props: {
}): JSX.Element {
return (
<ListItem expanded={!!props.children} className={classNames("flex-col")}>
<div className={classNames("flex flex-1 space-x-2 w-full p-3 items-center")}>
<div className={classNames("flex flex-1 rtl:space-x-reverse space-x-2 w-full p-3 items-center")}>
<Image width={40} height={40} src={`/${props.imageSrc}`} alt={props.title} />
<div className="flex-grow pl-2 truncate">
<ListItemTitle component="h3">{props.title}</ListItemTitle>

View file

@ -95,7 +95,7 @@ const CustomInputTypeForm: FC<Props> = (props) => {
<input
id="required"
type="checkbox"
className="w-4 h-4 mr-2 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
className="w-4 h-4 ltr:mr-2 rtl:ml-2 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
defaultChecked={selectedCustomInput?.required ?? true}
{...register("required")}
/>
@ -117,7 +117,7 @@ const CustomInputTypeForm: FC<Props> = (props) => {
/>
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit">{t("save")}</Button>
<Button onClick={onCancel} type="button" color="secondary" className="mr-2">
<Button onClick={onCancel} type="button" color="secondary" className="ltr:mr-2">
{t("cancel")}
</Button>
</div>

View file

@ -57,12 +57,12 @@ const ChangePasswordSection = () => {
return (
<>
<div className="mt-6">
<h2 className="font-cal text-lg leading-6 font-medium text-gray-900">{t("change_password")}</h2>
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">{t("change_password")}</h2>
</div>
<form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={changePasswordHandler}>
<div className="py-6 lg:pb-8">
<div className="flex">
<div className="w-1/2 mr-2">
<div className="w-1/2 ltr:mr-2 rtl:ml-2">
<label htmlFor="current_password" className="block text-sm font-medium text-gray-700">
{t("current_password")}
</label>
@ -74,7 +74,7 @@ const ChangePasswordSection = () => {
name="current_password"
id="current_password"
required
className="shadow-sm focus:ring-black focus:border-brand block w-full sm:text-sm border-gray-300 rounded-sm"
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-brand sm:text-sm"
placeholder={t("your_old_password")}
/>
</div>
@ -91,14 +91,14 @@ const ChangePasswordSection = () => {
value={newPassword}
required
onInput={(e) => setNewPassword(e.currentTarget.value)}
className="shadow-sm focus:ring-black focus:border-brand block w-full sm:text-sm border-gray-300 rounded-sm"
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-brand sm:text-sm"
placeholder={t("super_secure_new_password")}
/>
</div>
</div>
</div>
{errorMessage && <p className="mt-1 text-sm text-red-700">{errorMessage}</p>}
<div className="py-8 flex justify-end">
<div className="flex justify-end py-8">
<Button type="submit">{t("save")}</Button>
</div>
<hr className="mt-4" />

View file

@ -81,7 +81,7 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button
type="submit"
className="ml-2"
className="ltr:ml-2 rtl:mr-2"
onClick={handleDisable}
disabled={password.length === 0 || isDisabling}>
{t("disable")}

View file

@ -185,21 +185,24 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
<WithStep step={SetupStep.ConfirmPassword} current={step}>
<Button
type="submit"
className="ml-2"
className="ltr:ml-2 rtl:mr-2"
onClick={handleSetup}
disabled={password.length === 0 || isSubmitting}>
{t("continue")}
</Button>
</WithStep>
<WithStep step={SetupStep.DisplayQrCode} current={step}>
<Button type="submit" className="ml-2" onClick={() => setStep(SetupStep.EnterTotpCode)}>
<Button
type="submit"
className="ltr:ml-2 rtl:mr-2"
onClick={() => setStep(SetupStep.EnterTotpCode)}>
{t("continue")}
</Button>
</WithStep>
<WithStep step={SetupStep.EnterTotpCode} current={step}>
<Button
type="submit"
className="ml-2"
className="ltr:ml-2 rtl:mr-2"
onClick={handleEnable}
disabled={totpCode.length !== 6 || isSubmitting}>
{t("enable")}

View file

@ -72,7 +72,7 @@ export default function MemberChangeRoleModal(props: {
</p>
)}
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit" color="primary" className="ml-2">
<Button type="submit" color="primary" className="ltr:ml-2 rtl:mr-2">
{t("save")}
</Button>
<Button type="button" color="secondary" onClick={props.onExit}>

View file

@ -111,7 +111,7 @@ export default function MemberInvitationModal(props: { team: TeamWithMembers | n
className="text-black border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
/>
</div>
<div className="ml-2 text-sm">
<div className="ltr:ml-2 rtl:mr-2text-sm">
<label htmlFor="sendInviteEmail" className="font-medium text-gray-700">
{t("send_invite_email")}
</label>
@ -125,7 +125,11 @@ export default function MemberInvitationModal(props: { team: TeamWithMembers | n
</p>
)}
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<Button type="submit" color="primary" className="ml-2" data-testid="invite-new-member-button">
<Button
type="submit"
color="primary"
className="ltr:ml-2 rtl:mr-2"
data-testid="invite-new-member-button">
{t("invite")}
</Button>
<Button type="button" color="secondary" onClick={props.onExit}>

View file

@ -79,7 +79,7 @@ export default function MemberListItem(props: Props) {
</span>
</div>
</div>
<div className="flex mt-2 mr-2 sm:mt-0 sm:justify-center">
<div className="flex mt-2 ltr:mr-2 rtl:ml-2 sm:mt-0 sm:justify-center">
{!props.member.accepted && <TeamRole invitePending />}
<TeamRole role={props.member.role} />
</div>
@ -167,7 +167,7 @@ export default function MemberListItem(props: Props) {
{showTeamAvailabilityModal && (
<ModalContainer wide noPadding>
<TeamAvailabilityModal team={props.team} member={props.member} />
<div className="p-5 space-x-2 border-t">
<div className="p-5 rtl:space-x-reverse space-x-2 border-t">
<Button onClick={() => setShowTeamAvailabilityModal(false)}>{t("done")}</Button>
{props.team.membership.role !== MembershipRole.MEMBER && (
<Link href={`/settings/teams/${props.team.id}/availability`}>

View file

@ -74,7 +74,7 @@ export default function TeamCreate(props: Props) {
<button type="submit" className="btn btn-primary">
{t("create_team")}
</button>
<button onClick={props.onClose} type="button" className="mr-2 btn btn-white">
<button onClick={props.onClose} type="button" className="ltr:mr-2 btn btn-white">
{t("cancel")}
</button>
</div>

View file

@ -93,13 +93,13 @@ export default function TeamListItem(props: Props) {
<Button type="button" color="secondary" onClick={declineInvite}>
{t("reject")}
</Button>
<Button type="button" color="primary" className="ml-2" onClick={acceptInvite}>
<Button type="button" color="primary" className="ltr:ml-2 rtl:mr-2" onClick={acceptInvite}>
{t("accept")}
</Button>
</>
)}
{!isInvitee && (
<div className="flex space-x-2">
<div className="flex rtl:space-x-reverse space-x-2">
<TeamRole role={team.role as MembershipRole} />
<Tooltip content={t("copy_link_team")}>

View file

@ -13,12 +13,15 @@ export default function TeamRole(props: Props) {
return (
<span
className={classNames("self-center px-3 py-1 mr-2 text-xs capitalize border rounded-md", {
"bg-blue-50 border-blue-200 text-blue-700": props.role === "MEMBER",
"bg-gray-50 border-gray-200 text-gray-700": props.role === "OWNER",
"bg-red-50 border-red-200 text-red-700": props.role === "ADMIN",
"bg-yellow-50 border-yellow-200 text-yellow-700": props.invitePending,
})}>
className={classNames(
"self-center px-3 py-1 ltr:mr-2 rtl:ml-2 text-xs capitalize border rounded-md",
{
"bg-blue-50 border-blue-200 text-blue-700": props.role === "MEMBER",
"bg-gray-50 border-gray-200 text-gray-700": props.role === "OWNER",
"bg-red-50 border-red-200 text-red-700": props.role === "ADMIN",
"bg-yellow-50 border-yellow-200 text-yellow-700": props.invitePending,
}
)}>
{(() => {
if (props.invitePending) return t("invitee");
switch (props.role) {

View file

@ -188,7 +188,7 @@ export default function TeamSettings(props: Props) {
className="w-4 h-4 border-gray-300 rounded-sm focus:ring-neutral-500 text-neutral-900"
/>
</div>
<div className="ml-3 text-sm">
<div className="text-sm ltr:ml-3 rtl:mr-3">
<label htmlFor="hide-branding" className="font-medium text-gray-700">
{t("disable_cal_branding")}
</label>

View file

@ -27,7 +27,7 @@ export const AvatarGroup = function AvatarGroup(props: AvatarGroupProps) {
: [];*/
return (
<ul className={classNames("flex -space-x-2 overflow-hidden", props.className)}>
<ul className={classNames("flex -rtl:space-x-reverse space-x-2 overflow-hidden", props.className)}>
{props.items.slice(0, props.truncateAfter).map((item, idx) => {
if (item.image != null) {
return (

View file

@ -90,7 +90,12 @@ export const Button = forwardRef<HTMLAnchorElement | HTMLButtonElement, ButtonPr
},
<>
{StartIcon && (
<StartIcon className={classNames("inline", size === "icon" ? "w-5 h-5 " : "w-5 h-5 mr-2 -ml-1")} />
<StartIcon
className={classNames(
"inline",
size === "icon" ? "w-5 h-5 " : "w-5 h-5 ltr:mr-2 rtl:ml-2 rtl:ml-2 rtl:-mr-1 -ml-1"
)}
/>
)}
{props.children}
{loading && (
@ -117,7 +122,7 @@ export const Button = forwardRef<HTMLAnchorElement | HTMLButtonElement, ButtonPr
</svg>
</div>
)}
{EndIcon && <EndIcon className="inline w-5 h-5 ml-2 -mr-1" />}
{EndIcon && <EndIcon className="inline w-5 h-5 ltr:ml-2 rtl:mr-2 -mr-1" />}
</>
);
return props.href ? (

View file

@ -12,7 +12,7 @@ export const DropdownMenuTrigger = forwardRef<HTMLButtonElement, DropdownMenuTri
className={
props.asChild
? className
: `relative inline-flex items-center px-3 py-2 ml-2 text-sm font-medium text-gray-700 bg-transparent rounded-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-gray-100 focus:ring-neutral-500 group-hover:text-black ${className}`
: `relative inline-flex items-center px-3 py-2 ltr:ml-2 rtl:mr-2 text-sm font-medium text-gray-700 bg-transparent rounded-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-gray-100 focus:ring-neutral-500 group-hover:text-black ${className}`
}
ref={forwardedRef}
/>

View file

@ -13,7 +13,7 @@ export default function LinkIconButton(props: LinkIconButtonProps) {
{...props}
type="button"
className="flex items-center px-2 py-1 text-sm font-medium text-gray-700 rounded-sm text-md hover:text-gray-900 hover:bg-gray-200">
<props.Icon className="w-4 h-4 mr-2 text-neutral-500" />
<props.Icon className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-neutral-500" />
{props.children}
</button>
</div>

View file

@ -14,7 +14,7 @@ export default function SettingInputContainer({
<div className="block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor={htmlFor} className="flex mt-1 text-sm font-medium text-neutral-700">
<Icon className="w-4 h-4 mr-2 mt-0.5 text-neutral-500" />
<Icon className="w-4 h-4 ltr:mr-2 rtl:ml-2 mt-0.5 text-neutral-500" />
{label}
</label>
</div>

View file

@ -37,7 +37,7 @@ export default function Switch(props: SwitchProps) {
{label && (
<Label.Root
htmlFor={id}
className="text-neutral-700 text-sm align-text-top ml-3 font-medium cursor-pointer">
className="text-sm font-medium align-text-top cursor-pointer text-neutral-700 ltr:ml-3 rtl:mr-3">
{label}
</Label.Root>
)}

View file

@ -24,7 +24,7 @@ const TableActions: FC<Props> = ({ actions }) => {
const { t } = useLocale();
return (
<>
<div className="space-x-2 hidden lg:block">
<div className="rtl:space-x-reverse space-x-2 hidden lg:block">
{actions.map((action) => (
<Button
key={action.id}
@ -74,7 +74,7 @@ const TableActions: FC<Props> = ({ actions }) => {
"group flex items-center px-4 py-2 text-sm font-medium"
)}>
<action.icon
className="mr-3 h-5 w-5 text-neutral-400 group-hover:text-neutral-500"
className="ltr:mr-3 h-5 w-5 text-neutral-400 group-hover:text-neutral-500"
aria-hidden="true"
/>
{action.label}

View file

@ -23,7 +23,7 @@ const CheckboxField = forwardRef<HTMLInputElement, Props>(({ label, description,
className="w-4 h-4 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
/>
</div>
<div className="ml-3 text-sm">
<div className="ltr:ml-3 rtl:mr-3 text-sm">
<p className="text-neutral-900">{description}</p>
</div>
</div>

View file

@ -80,7 +80,7 @@ export const CheckedSelect = React.forwardRef((props: CheckedSelectProps, ref: F
{selectedOptions.map((option) => (
<div key={option.value} className="border border-1 p-2 font-medium">
<Avatar
className="w-6 h-6 rounded-full inline mr-2"
className="w-6 h-6 rounded-full inline ltr:mr-2 rtl:ml-2"
imageSrc={option.avatar}
displayName={option.label}
/>

View file

@ -17,7 +17,7 @@ export const DateRangePicker = ({ startDate, endDate, onDatesChange }: Props) =>
className="border-gray-300 rounded-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
clearIcon={null}
calendarIcon={<CalendarIcon className="h-5 w-5 text-gray-500" />}
rangeDivider={<ArrowRightIcon className="h-4 w-4 text-gray-400 mr-2" />}
rangeDivider={<ArrowRightIcon className="h-4 w-4 text-gray-400 ltr:mr-2 rtl:ml-2" />}
value={[startDate, endDate]}
onChange={([startDate, endDate]) => {
onDatesChange({ startDate, endDate });

View file

@ -123,7 +123,7 @@ const ScheduleBlock = ({ name, day, weekday }: ScheduleBlockProps) => {
return (
<fieldset className="flex flex-col space-y-2 sm:space-y-0 sm:flex-row justify-between py-5 min-h-[86px]">
<div className="w-1/3">
<label className="flex items-center space-x-2">
<label className="flex items-center rtl:space-x-reverse space-x-2">
<input
type="checkbox"
checked={fields.length > 0}
@ -136,7 +136,7 @@ const ScheduleBlock = ({ name, day, weekday }: ScheduleBlockProps) => {
<div className="flex-grow">
{fields.map((field, index) => (
<div key={field.id} className="flex justify-between mb-1">
<div className="flex items-center space-x-2">
<div className="flex items-center rtl:space-x-reverse space-x-2">
<TimeRangeField name={`${name}.${day}.${index}`} />
</div>
<Button

View file

@ -142,7 +142,7 @@ export default function SetTimesModal(props) {
<Button onClick={updateStartEndTimesHandler} type="submit">
{t("save")}
</Button>
<Button onClick={props.onExit} type="button" color="secondary" className="mr-2">
<Button onClick={props.onExit} type="button" color="secondary" className="ltr:mr-2">
{t("cancel")}
</Button>
</div>

View file

@ -24,40 +24,40 @@ export default function LicenseBanner() {
}
return (
<div className="fixed left-0 md:left-56 bottom-0 inset-x-0 pb-2 sm:pb-5">
<div className="max-w-7xl mx-auto px-2 sm:px-8">
<div className="p-2 rounded-sm bg-green-600 shadow-lg sm:p-3">
<div className="flex items-center justify-between flex-wrap">
<div className="w-0 flex-1 flex items-center">
<span className="flex p-2 rounded-sm bg-green-800">
<BadgeCheckIcon className="h-6 w-6 text-white" aria-hidden="true" />
<div className="fixed inset-x-0 bottom-0 left-0 pb-2 md:left-56 sm:pb-5">
<div className="px-2 mx-auto max-w-7xl sm:px-8">
<div className="p-2 bg-green-600 rounded-sm shadow-lg sm:p-3">
<div className="flex flex-wrap items-center justify-between">
<div className="flex items-center flex-1 w-0">
<span className="flex p-2 bg-green-800 rounded-sm">
<BadgeCheckIcon className="w-6 h-6 text-white" aria-hidden="true" />
</span>
<p className="ml-3 font-medium text-white truncate">
<span className="inline">
<Trans i18nKey="accept_our_license" values={{ agree: "agree" }}>
Accept our license by changing the .env variable{" "}
<span className="bg-gray-50 bg-opacity-20 px-1">NEXT_PUBLIC_LICENSE_CONSENT</span> to
<span className="px-1 bg-gray-50 bg-opacity-20">NEXT_PUBLIC_LICENSE_CONSENT</span> to
&apos;agree&apos;.
</Trans>
</span>
</p>
</div>
<div className="order-3 mt-2 flex-shrink-0 w-full sm:order-2 sm:mt-0 sm:w-auto">
<div className="flex-shrink-0 order-3 w-full mt-2 sm:order-2 sm:mt-0 sm:w-auto">
<Dialog>
<DialogTrigger asChild>
<button className="rounded-sm w-full flex items-center justify-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium text-green-600 bg-white hover:bg-green-50">
<button className="flex items-center justify-center w-full px-4 py-2 text-sm font-medium text-green-600 bg-white border border-transparent rounded-sm shadow-sm hover:bg-green-50">
{t("accept_license")}
</button>
</DialogTrigger>
<DialogContent />
</Dialog>
</div>
<div className="order-2 flex-shrink-0 sm:order-3 sm:ml-2">
<div className="flex-shrink-0 order-2 sm:order-3 sm:ml-2">
<Dialog>
<DialogTrigger asChild>
<button className="-mr-1 flex p-2 rounded-sm hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-white">
<button className="flex p-2 -mr-1 rounded-sm hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-white">
<span className="sr-only">{t("dismiss")}</span>
<XIcon className="h-6 w-6 text-white" aria-hidden="true" />
<XIcon className="w-6 h-6 text-white" aria-hidden="true" />
</button>
</DialogTrigger>
<DialogContent />

View file

@ -149,7 +149,7 @@ export default function SAMLConfiguration({
<div className="flex justify-end py-8">
<button
type="submit"
className="ml-2 bg-neutral-900 border border-transparent rounded-sm shadow-sm py-2 px-4 inline-flex justify-center text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
className="ltr:ml-2 rtl:mr-2bg-neutral-900 border border-transparent rounded-sm shadow-sm py-2 px-4 inline-flex justify-center text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
{t("save")}
</button>
</div>

View file

@ -32,7 +32,7 @@ export default function TeamAvailabilityModal(props: Props) {
}, [utils, selectedTimeZone, selectedDate]);
return (
<div className="flex flex-row max-h-[500px] min-h-[500px] space-x-8">
<div className="flex flex-row max-h-[500px] min-h-[500px] rtl:space-x-reverse space-x-8">
<div className="w-64 p-5 pr-0 space-y-5 min-w-64">
<div className="flex">
<Avatar

View file

@ -62,7 +62,7 @@ export default function TeamAvailabilityScreen(props: Props) {
return (
<div className="flex flex-col flex-1 bg-white border rounded-sm border-neutral-200">
<div className="flex w-full p-4 space-x-5 border-b border-gray-200">
<div className="flex w-full p-4 rtl:space-x-reverse space-x-5 border-b border-gray-200">
<div className="flex flex-col">
<span className="text-sm font-medium text-neutral-700">Date</span>
<DatePicker

View file

@ -20,7 +20,7 @@ const HelpMenuItem = () => {
<ChatAltIcon
className={classNames(
"text-neutral-400 group-hover:text-neutral-500",
"mr-2 flex-shrink-0 h-5 w-5"
"ltr:mr-2 flex-shrink-0 h-5 w-5"
)}
aria-hidden="true"
/>

View file

@ -78,7 +78,7 @@ export default function Custom404() {
<li className="px-4 py-2 border-2 border-green-500">
<a
href={"https://cal.com/signup?username=" + username.replace("/", "")}
className="relative flex items-start py-6 space-x-4">
className="relative flex items-start py-6 rtl:space-x-reverse space-x-4">
<div className="flex-shrink-0">
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-green-50">
<CheckIcon className="w-6 h-6 text-green-500" aria-hidden="true" />
@ -107,7 +107,7 @@ export default function Custom404() {
{links.map((link, linkIdx) => (
<li key={linkIdx} className="px-4 py-2">
<Link href={link.href}>
<a className="relative flex items-start py-6 space-x-4">
<a className="relative flex items-start py-6 rtl:space-x-reverse space-x-4">
<div className="flex-shrink-0">
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-gray-50">
<link.icon className="w-6 h-6 text-gray-700" aria-hidden="true" />
@ -130,7 +130,9 @@ export default function Custom404() {
</li>
))}
<li className="px-4 py-2">
<a href="https://cal.com/slack" className="relative flex items-start py-6 space-x-4">
<a
href="https://cal.com/slack"
className="relative flex items-start py-6 rtl:space-x-reverse space-x-4">
<div className="flex-shrink-0">
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-gray-50">
<svg viewBox="0 0 2447.6 2452.5" className="w-6 h-6" xmlns="http://www.w3.org/2000/svg">

View file

@ -9,8 +9,11 @@ class MyDocument extends Document<Props> {
}
render() {
const { locale } = this.props.__NEXT_DATA__;
const dir = locale === "ar" || locale === "he" ? "rtl" : "ltr";
return (
<Html>
<Html lang={locale} dir={dir}>
<Head>
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
@ -20,7 +23,7 @@ class MyDocument extends Document<Props> {
<meta name="msapplication-TileColor" content="#ff0000" />
<meta name="theme-color" content="#ffffff" />
</Head>
<body className="dark:bg-black bg-gray-100">
<body className="bg-gray-100 dark:bg-black">
<Main />
<NextScript />
</body>

View file

@ -115,7 +115,7 @@ export default function Signup({ email }: Props) {
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-black focus:border-black sm:text-sm"
/>
</div>
<div className="flex space-x-2">
<div className="flex rtl:space-x-reverse space-x-2">
<Button loading={isSubmitting} className="justify-center w-7/12">
{t("create_account")}
</Button>

View file

@ -58,7 +58,7 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
<Button>{t("save")}</Button>
</div>
</Form>
<div className="col-span-3 ml-2 lg:col-span-1 min-w-40">
<div className="col-span-3 ltr:ml-2 rtl:mr-2 lg:col-span-1 min-w-40">
<div className="px-4 py-5 border border-gray-200 rounded-sm sm:p-6 ">
<h3 className="text-base font-medium leading-6 text-gray-900">
{t("something_doesnt_look_right")}

View file

@ -99,7 +99,7 @@ export default function Type(props: inferSSRProps<typeof getServerSideProps>) {
onChange={(e) => setCancellationReason(e.target.value)}
className="mb-5 sm:mb-6"
/>
<div className="text-center space-x-2">
<div className="text-center rtl:space-x-reverse space-x-2">
<Button
color="secondary"
data-testid="cancel"

View file

@ -380,13 +380,13 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
{location.type === LocationType.InPerson && (
<div className="flex items-center flex-grow">
<LocationMarkerIcon className="w-6 h-6" />
<span className="ml-2 text-sm">{location.address}</span>
<span className="ltr:ml-2 rtl:mr-2text-sm">{location.address}</span>
</div>
)}
{location.type === LocationType.Phone && (
<div className="flex items-center flex-grow">
<PhoneIcon className="w-6 h-6" />
<span className="ml-2 text-sm">{t("phone_call")}</span>
<span className="ltr:ml-2 rtl:mr-2text-sm">{t("phone_call")}</span>
</div>
)}
{location.type === LocationType.GoogleMeet && (
@ -417,7 +417,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<path d="M0 16H16V37.3333H0" fill="#2684FC" />
</svg>
<span className="ml-2 text-sm">Google Meet</span>
<span className="ltr:ml-2 rtl:mr-2text-sm">Google Meet</span>
</div>
)}
{location.type === LocationType.Daily && (
@ -462,7 +462,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
fillRule="evenodd"></path>
</g>
</svg>
<span className="ml-2 text-sm">Daily.co Video</span>
<span className="ltr:ml-2 rtl:mr-2text-sm">Daily.co Video</span>
</div>
)}
{location.type === LocationType.Zoom && (
@ -489,7 +489,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
fill="white"
/>
</svg>
<span className="ml-2 text-sm">Zoom Video</span>
<span className="ltr:ml-2 rtl:mr-2text-sm">Zoom Video</span>
</div>
)}
<div className="flex">
@ -558,7 +558,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
}
subtitle={eventType.description || ""}>
<div className="block mx-auto sm:flex md:max-w-5xl">
<div className="w-full mr-2 sm:w-9/12">
<div className="w-full ltr:mr-2 rtl:ml-2 sm:w-9/12">
<div className="p-4 py-6 -mx-4 bg-white border rounded-sm border-neutral-200 sm:mx-0 sm:px-8">
<Form
form={formMethods}
@ -581,7 +581,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="slug" className="flex text-sm font-medium text-neutral-700">
<LinkIcon className="w-4 h-4 mr-2 mt-0.5 text-neutral-500" />
<LinkIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 mt-0.5 text-neutral-500" />
{t("url")}
</label>
</div>
@ -609,7 +609,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<MinutesField
label={
<>
<ClockIcon className="w-4 h-4 mr-2 mt-0.5 text-neutral-500" /> {t("duration")}
<ClockIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 mt-0.5 text-neutral-500" />{" "}
{t("duration")}
</>
}
id="length"
@ -629,7 +630,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="block sm:flex">
<div className="min-w-48 sm:mb-0">
<label htmlFor="location" className="flex mt-2.5 text-sm font-medium text-neutral-700">
<LocationMarkerIcon className="w-4 h-4 mr-2 mt-0.5 text-neutral-500" />
<LocationMarkerIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 mt-0.5 text-neutral-500" />
{t("location")}
</label>
</div>
@ -646,7 +647,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0 mt-2.5">
<label htmlFor="description" className="flex mt-0 text-sm font-medium text-neutral-700">
<DocumentIcon className="w-4 h-4 mr-2 mt-0.5 text-neutral-500" />
<DocumentIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 mt-0.5 text-neutral-500" />
{t("description")}
</label>
</div>
@ -668,7 +669,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<label
htmlFor="schedulingType"
className="flex mt-2 text-sm font-medium text-neutral-700">
<UsersIcon className="w-5 h-5 mr-2 text-neutral-500" /> {t("scheduling_type")}
<UsersIcon className="w-5 h-5 ltr:mr-2 rtl:ml-2 text-neutral-500" />{" "}
{t("scheduling_type")}
</label>
</div>
<Controller
@ -693,7 +695,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="users" className="flex text-sm font-medium text-neutral-700">
<UserAddIcon className="w-5 h-5 mr-2 text-neutral-500" /> {t("attendees")}
<UserAddIcon className="w-5 h-5 ltr:mr-2 rtl:ml-2 text-neutral-500" />{" "}
{t("attendees")}
</label>
</div>
<div className="w-full space-y-2">
@ -823,7 +826,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="flex-1 w-0">
<div className="truncate">
<span
className="ml-2 text-sm"
className="ltr:ml-2 rtl:mr-2text-sm"
title={`${t("label")}: ${customInput.label}`}>
{t("label")}: {customInput.label}
</span>
@ -831,19 +834,19 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
{customInput.placeholder && (
<div className="truncate">
<span
className="ml-2 text-sm"
className="ltr:ml-2 rtl:mr-2text-sm"
title={`${t("placeholder")}: ${customInput.placeholder}`}>
{t("placeholder")}: {customInput.placeholder}
</span>
</div>
)}
<div>
<span className="ml-2 text-sm">
<span className="ltr:ml-2 rtl:mr-2text-sm">
{t("type")}: {customInput.type}
</span>
</div>
<div>
<span className="ml-2 text-sm">
<span className="ltr:ml-2 rtl:mr-2text-sm">
{customInput.required ? t("required") : t("optional")}
</span>
</div>
@ -1007,7 +1010,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<RadioGroup.Item
id={period.type}
value={period.type}
className="flex items-center w-4 h-4 mr-2 bg-white border border-black rounded-full cursor-pointer focus:border-2 focus:outline-none">
className="flex items-center w-4 h-4 bg-white border border-black rounded-full cursor-pointer ltr:mr-2 rtl:ml-2 focus:border-2 focus:outline-none">
<RadioGroup.Indicator className="relative flex items-center justify-center w-4 h-4 after:bg-black after:block after:w-2 after:h-2 after:rounded-full" />
</RadioGroup.Item>
{period.prefix ? <span>{period.prefix}&nbsp;</span> : null}
@ -1015,7 +1018,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="inline-flex">
<input
type="number"
className="block w-12 mr-2 border-gray-300 rounded-sm shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm [appearance:textfield]"
className="block w-12 ltr:mr-2 rtl:ml-2 border-gray-300 rounded-sm shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm [appearance:textfield]"
placeholder="30"
{...formMethods.register("periodDays", { valueAsNumber: true })}
defaultValue={eventType.periodDays || 30}
@ -1031,7 +1034,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
)}
{period.type === "RANGE" && (
<div className="inline-flex ml-2 space-x-2">
<div className="inline-flex rtl:space-x-reverse space-x-2 ltr:ml-2 rtl:mr-2">
<Controller
name="periodDates"
control={formMethods.control}
@ -1049,7 +1052,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
)}
{period.suffix ? (
<span className="ml-2">&nbsp;{period.suffix}</span>
<span className="ltr:ml-2 rtl:mr-2">&nbsp;{period.suffix}</span>
) : null}
</div>
))}
@ -1127,7 +1130,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
defaultChecked={requirePayment}
/>
</div>
<div className="ml-3 text-sm">
<div className="ltr:ml-3 rtl:mr-3 text-sm">
<p className="text-neutral-900">
{t("require_payment")} (0.5% +{" "}
<IntlProvider locale="en">
@ -1194,7 +1197,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</>
{/* )} */}
</Collapsible>
<div className="flex justify-end mt-4 space-x-2">
<div className="flex justify-end mt-4 rtl:space-x-reverse space-x-2">
<Button href="/event-types" color="secondary" tabIndex={-1}>
{t("cancel")}
</Button>
@ -1205,7 +1208,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</Form>
</div>
</div>
<div className="w-full px-2 mt-8 ml-2 sm:w-3/12 sm:mt-0 min-w-[177px] ">
<div className="w-full px-2 mt-8 ltr:ml-2 rtl:mr-2 sm:w-3/12 sm:mt-0 min-w-[177px] ">
<div className="px-2">
<Controller
name="hidden"
@ -1228,7 +1231,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
target="_blank"
rel="noreferrer"
className="inline-flex items-center px-2 py-1 text-sm font-medium rounded-sm text-md text-neutral-700 hover:text-gray-900 hover:bg-gray-200">
<ExternalLinkIcon className="w-4 h-4 mr-2 text-neutral-500" aria-hidden="true" />
<ExternalLinkIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-neutral-500" aria-hidden="true" />
{t("preview")}
</a>
<button
@ -1238,12 +1241,12 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
}}
type="button"
className="flex items-center px-2 py-1 text-sm font-medium text-gray-700 rounded-sm text-md hover:text-gray-900 hover:bg-gray-200">
<LinkIcon className="w-4 h-4 mr-2 text-neutral-500" />
<LinkIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-neutral-500" />
{t("copy_link")}
</button>
<Dialog>
<DialogTrigger className="flex items-center px-2 py-1 text-sm font-medium rounded-sm text-md text-neutral-700 hover:text-gray-900 hover:bg-gray-200">
<TrashIcon className="w-4 h-4 mr-2 text-neutral-500" />
<TrashIcon className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-neutral-500" />
{t("delete")}
</DialogTrigger>
<ConfirmationDialogContent
@ -1327,7 +1330,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
onClick={() => setShowLocationModal(false)}
type="button"
color="secondary"
className="mr-2">
className="ltr:mr-2">
{t("cancel")}
</Button>
</div>

View file

@ -131,12 +131,12 @@ const EventTypeList = ({ readOnly, types, profile }: EventTypeListProps): JSX.El
<span className="font-medium truncate text-neutral-900">{type.title} </span>
<small className="hidden sm:inline text-neutral-500">{`/${profile.slug}/${type.slug}`}</small>
{type.hidden && (
<span className="ml-2 inline items-center px-1.5 py-0.5 rounded-sm text-xs font-medium bg-yellow-100 text-yellow-800">
<span className="ltr:ml-2 rtl:mr-2inline items-center px-1.5 py-0.5 rounded-sm text-xs font-medium bg-yellow-100 text-yellow-800">
{t("hidden")}
</span>
)}
{readOnly && (
<span className="ml-2 inline items-center px-1.5 py-0.5 rounded-sm text-xs font-medium bg-gray-100 text-gray-800">
<span className="ltr:ml-2 rtl:mr-2inline items-center px-1.5 py-0.5 rounded-sm text-xs font-medium bg-gray-100 text-gray-800">
{t("readonly")}
</span>
)}
@ -146,7 +146,7 @@ const EventTypeList = ({ readOnly, types, profile }: EventTypeListProps): JSX.El
</Link>
<div className="flex-shrink-0 hidden mt-4 sm:flex sm:mt-0 sm:ml-5">
<div className="flex items-center space-x-2 overflow-hidden">
<div className="flex items-center rtl:space-x-reverse space-x-2 overflow-hidden">
{type.users?.length > 1 && (
<AvatarGroup
size={8}
@ -272,7 +272,7 @@ const EventTypeListHeading = ({ profile, membershipCount }: EventTypeListHeading
alt={profile?.name || ""}
imageSrc={profile?.image || undefined}
size={8}
className="inline mt-1 mr-2"
className="inline mt-1 ltr:mr-2 rtl:ml-2"
/>
</a>
</Link>
@ -281,7 +281,7 @@ const EventTypeListHeading = ({ profile, membershipCount }: EventTypeListHeading
<a className="font-bold">{profile?.name || ""}</a>
</Link>
{membershipCount && (
<span className="relative ml-2 text-xs text-neutral-500 -top-px">
<span className="relative ltr:ml-2 rtl:mr-2 text-xs text-neutral-500 -top-px">
<Link href="/settings/teams">
<a>
<Badge variant="gray">

View file

@ -534,7 +534,7 @@ export default function Onboarding(props: inferSSRProps<typeof getServerSideProp
{error && <Alert severity="error" {...error} />}
<section className="flex w-full space-x-2">
<section className="flex w-full rtl:space-x-reverse space-x-2">
{steps.map((s, index) => {
return index <= currentStep ? (
<div

View file

@ -56,7 +56,7 @@ function WebhookListItem(props: { webhook: TWebhook; onEditWebhook: () => void }
</span>
</div>
<div className="flex mt-2">
<span className="flex flex-col space-y-1 text-xs sm:space-y-0 sm:flex-row sm:space-x-2">
<span className="flex flex-col space-y-1 text-xs sm:space-y-0 sm:flex-row sm:rtl:space-x-reverse space-x-2">
{props.webhook.eventTriggers.map((eventTrigger, ind) => (
<span
key={ind}
@ -249,7 +249,7 @@ function WebhookDialogForm(props: {
</fieldset>
<fieldset className="space-y-2">
<FieldsetLegend>{t("payload_template")}</FieldsetLegend>
<div className="space-x-3 text-sm">
<div className="rtl:space-x-reverse space-x-3 text-sm">
<label>
<input
className="text-neutral-900 focus:ring-neutral-500"
@ -307,7 +307,8 @@ function WebhookListContainer() {
<ShellSubHeading className="mt-10" title={t("Webhooks")} subtitle={t("receive_cal_meeting_data")} />
<List>
<ListItem className={classNames("flex-col")}>
<div className={classNames("flex flex-1 space-x-2 w-full p-3 items-center")}>
<div
className={classNames("flex flex-1 rtl:space-x-reverse space-x-2 w-full p-3 items-center")}>
<Image width={40} height={40} src="/integrations/webhooks.svg" alt="Webhooks" />
<div className="flex-grow pl-2 truncate">
<ListItemTitle component="h3">Webhooks</ListItemTitle>
@ -380,7 +381,7 @@ function IframeEmbedContainer() {
<div className="lg:pb-8 lg:col-span-9">
<List>
<ListItem className={classNames("flex-col")}>
<div className={classNames("flex flex-1 space-x-2 w-full p-3 items-center")}>
<div className={classNames("flex flex-1 rtl:space-x-reverse space-x-2 w-full p-3 items-center")}>
<Image width={40} height={40} src="/integrations/embed.svg" alt="Embed" />
<div className="flex-grow pl-2 truncate">
<ListItemTitle component="h3">{t("standard_iframe")}</ListItemTitle>
@ -399,13 +400,13 @@ function IframeEmbedContainer() {
navigator.clipboard.writeText(iframeTemplate);
showToast("Copied to clipboard", "success");
}}>
<ClipboardIcon className="w-4 h-4 -mb-0.5 mr-2 text-gray-800" />
<ClipboardIcon className="w-4 h-4 -mb-0.5 ltr:mr-2 rtl:ml-2 text-gray-800" />
</button>
</div>
</div>
</ListItem>
<ListItem className={classNames("flex-col")}>
<div className={classNames("flex flex-1 space-x-2 w-full p-3 items-center")}>
<div className={classNames("flex flex-1 rtl:space-x-reverse space-x-2 w-full p-3 items-center")}>
<Image width={40} height={40} src="/integrations/embed.svg" alt="Embed" />
<div className="flex-grow pl-2 truncate">
<ListItemTitle component="h3">{t("responsive_fullscreen_iframe")}</ListItemTitle>
@ -424,13 +425,13 @@ function IframeEmbedContainer() {
navigator.clipboard.writeText(htmlTemplate);
showToast("Copied to clipboard", "success");
}}>
<ClipboardIcon className="w-4 h-4 -mb-0.5 mr-2 text-gray-800" />
<ClipboardIcon className="w-4 h-4 -mb-0.5 ltr:mr-2 rtl:ml-2 text-gray-800" />
</button>
</div>
</div>
</ListItem>
</List>
<div className="grid grid-cols-2 space-x-4">
<div className="grid grid-cols-2 rtl:space-x-reverse space-x-4">
<div>
<label htmlFor="iframe" className="block text-sm font-medium text-gray-700"></label>
<div className="mt-1"></div>

View file

@ -33,7 +33,7 @@ export default function RadioAreaPage() {
<form onSubmit={onSubmit} className="space-y-4 mb-2">
<RadioArea.Group
onChange={(radioGroup_1: string) => setFormData({ ...formData, radioGroup_1 })}
className="flex space-x-4 max-w-screen-md"
className="flex rtl:space-x-reverse space-x-4 max-w-screen-md"
name="radioGroup_1">
<RadioArea.Item value="radioGroup_1_radio_1" className="flex-grow bg-white">
<strong className="mb-1">radioGroup_1_radio_1</strong>
@ -50,7 +50,7 @@ export default function RadioAreaPage() {
</RadioArea.Group>
<RadioArea.Group
onChange={(radioGroup_2: string) => setFormData({ ...formData, radioGroup_2 })}
className="flex space-x-4 max-w-screen-md"
className="flex rtl:space-x-reverse space-x-4 max-w-screen-md"
name="radioGroup_2">
<RadioArea.Item value="radioGroup_2_radio_1" className="flex-grow bg-white">
<strong className="mb-1">radioGroup_1_radio_1</strong>

View file

@ -213,8 +213,8 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
<div className="py-6 lg:pb-8">
<div className="flex flex-col lg:flex-row">
<div className="flex-grow space-y-6">
<div className="block sm:flex">
<div className="w-full mb-6 sm:w-1/2 sm:mr-2">
<div className="block space-x-2 sm:flex rtl:space-x-reverse">
<div className="w-full mb-6 sm:w-1/2">
<TextField
name="username"
addOnLeading={
@ -226,7 +226,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
defaultValue={props.user.username || undefined}
/>
</div>
<div className="w-full sm:w-1/2 sm:ml-2">
<div className="w-full sm:w-1/2">
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
{t("full_name")}
</label>
@ -244,7 +244,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
</div>
</div>
<div className="block sm:flex">
<div className="w-full mb-6 sm:w-1/2 sm:mr-2">
<div className="w-full mb-6 sm:w-1/2">
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
{t("email")}
</label>
@ -391,7 +391,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
className="w-4 h-4 border-gray-300 rounded-sm focus:ring-neutral-800 text-neutral-900"
/>
</div>
<div className="ml-3 text-sm">
<div className="text-sm ltr:ml-3 rtl:mr-3">
<label htmlFor="theme-adjust-os" className="font-medium text-gray-700">
{t("automatically_adjust_theme")}
</label>
@ -420,7 +420,7 @@ function SettingsView(props: ComponentProps<typeof Settings> & { localeProp: str
<div className="flex items-center h-5">
<HideBrandingInput user={props.user} hideBrandingRef={hideBrandingRef} />
</div>
<div className="ml-3 text-sm">
<div className="text-sm ltr:ml-3 rtl:mr-3">
<label htmlFor="hide-branding" className="font-medium text-gray-700">
{t("disable_cal_branding")}{" "}
{props.user.plan !== "PRO" && <Badge variant="default">PRO</Badge>}

View file

@ -63,7 +63,7 @@ export default function Teams() {
type="button"
className="btn btn-white"
onClick={() => setShowCreateTeamModal(true)}>
<PlusIcon className="group-hover:text-black text-gray-700 w-3.5 h-3.5 mr-2 inline-block" />
<PlusIcon className="group-hover:text-black text-gray-700 w-3.5 h-3.5 ltr:mr-2 rtl:ml-2 inline-block" />
{t("new_team")}
</Button>
</div>

View file

@ -53,7 +53,7 @@ export function TeamSettingsPage() {
{team && (
<>
<div className="block sm:flex md:max-w-5xl">
<div className="w-full mr-2 sm:w-9/12">
<div className="w-full ltr:mr-2 rtl:ml-2 sm:w-9/12">
<div className="px-4 -mx-0 bg-white border rounded-sm border-neutral-200 sm:px-6">
{isAdmin ? (
<TeamSettings team={team} />
@ -82,7 +82,7 @@ export function TeamSettingsPage() {
<MemberList team={team} members={team.members || []} />
{isAdmin ? <SAMLConfiguration teamsView={true} teamId={team.id} /> : null}
</div>
<div className="w-full px-2 mt-8 ml-2 md:w-3/12 sm:mt-0 min-w-32">
<div className="w-full px-2 mt-8 ltr:ml-2 rtl:mr-2 md:w-3/12 sm:mt-0 min-w-32">
<TeamSettingsRightSidebar role={team.membership.role} team={team} />
</div>
</div>

View file

@ -149,7 +149,7 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
</div>
{!needsConfirmation && (
<div className="flex pt-2 pb-4 mt-5 text-center border-b dark:border-gray-900 sm:mt-0 sm:pt-4">
<span className="flex self-center mr-2 font-medium text-gray-700 dark:text-gray-50">
<span className="flex self-center ltr:mr-2 rtl:ml-2 font-medium text-gray-700 dark:text-gray-50">
{t("add_to_calendar")}
</span>
<div className="flex justify-center flex-grow text-center">

View file

@ -180,7 +180,7 @@
.react-multi-email [data-tag] {
box-shadow: none !important;
@apply inline-flex items-center px-2 py-1 my-1 mr-2 text-sm font-medium text-gray-900 border border-transparent rounded-md dark:text-white bg-neutral-200 hover:bg-neutral-100 dark:bg-brand focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500;
@apply inline-flex items-center px-2 py-1 my-1 ltr:mr-2 rtl:ml-2 text-sm font-medium text-gray-900 border border-transparent rounded-md dark:text-white bg-neutral-200 hover:bg-neutral-100 dark:bg-brand focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500;
}
.react-multi-email > span[data-placeholder] {
@ -208,7 +208,7 @@
}
.react-multi-email [data-tag] {
@apply inline-flex items-center px-2 py-1 my-1 mr-2 text-sm font-medium text-gray-900 border border-transparent rounded-md shadow-sm dark:text-white bg-neutral-200 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500;
@apply inline-flex items-center px-2 py-1 my-1 ltr:mr-2 rtl:ml-2 text-sm font-medium text-gray-900 border border-transparent rounded-md shadow-sm dark:text-white bg-neutral-200 hover:bg-neutral-100 dark:bg-neutral-900 dark:hover:bg-neutral-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-500;
}
.react-multi-email [data-tag] [data-tag-item] {