Update commercial use trial wording

This commit is contained in:
Gregory Schier
2025-11-09 07:07:18 -08:00
parent 554e632c19
commit 9eddf716e1
4 changed files with 77 additions and 48 deletions

View File

@@ -10,6 +10,7 @@ import { Button } from '../core/Button';
import { Icon } from '../core/Icon'; import { Icon } from '../core/Icon';
import { Link } from '../core/Link'; import { Link } from '../core/Link';
import { PlainInput } from '../core/PlainInput'; import { PlainInput } from '../core/PlainInput';
import { Separator } from '../core/Separator';
import { HStack, VStack } from '../core/Stacks'; import { HStack, VStack } from '../core/Stacks';
import { LocalImage } from '../LocalImage'; import { LocalImage } from '../LocalImage';
@@ -34,43 +35,56 @@ function SettingsLicenseCmp() {
<div className="flex flex-col gap-6 max-w-xl"> <div className="flex flex-col gap-6 max-w-xl">
{check.data?.type === 'commercial_use' ? ( {check.data?.type === 'commercial_use' ? (
<Banner color="success">Your license is active 🥳</Banner> <Banner color="success">Your license is active 🥳</Banner>
) : check.data?.type == 'trialing' ? ( ) : check.data?.type === 'trialing' ? (
<Banner color="info" className="flex flex-col gap-3 max-w-lg"> <Banner color="info" className="@container flex items-center gap-x-5 max-w-xl">
<p> <LocalImage src="static/greg.jpeg" className="hidden @sm:block rounded-full h-14 w-14" />
<strong> <p className="w-full">
{pluralizeCount('day', differenceInDays(check.data.end, new Date()))} remaining <strong>{pluralizeCount('day', differenceInDays(check.data.end, new Date()))}</strong>{' '}
</strong>{' '} left to evaluate Yaak for commercial use.
on your commercial-use trial <br />
</p> <span className="opacity-50">Personal use is always free, forever.</span>
</Banner> <Separator className="my-2" />
) : check.data?.type == 'personal_use' ? ( <div className="flex flex-wrap items-center gap-x-2 text-sm text-notice">
<Banner color="notice" className="flex flex-col gap-3 max-w-lg"> <Link noUnderline href="mailto:support@yaak.app">
<p>You are able to use Yaak for personal use only</p> Contact Support
</Banner> </Link>
) : null} <Icon icon="dot" size="sm" color="secondary" />
{check.data?.type !== 'commercial_use' && (
<div className="grid grid-cols-[auto_minmax(0,1fr)] gap-6 items-center my-3 ">
<LocalImage src="static/greg.jpeg" className="rounded-full h-20 w-20" />
<div className="flex flex-col gap-2">
<h2 className="text-lg font-bold">Hey, I&apos;m Greg 👋🏼</h2>
<p>
Yaak is free for personal projects and learning.{' '}
{check.data?.type === 'trialing' ? 'Once your trial ends, a ' : 'A '}
license will be required for work or commercial use.
</p>
<p>
<Link <Link
noUnderline noUnderline
href={`https://yaak.app/pricing?s=learn&t=${check.data?.type ?? ''}`} href={`https://yaak.app/pricing?s=learn&t=${check.data?.type ?? ''}`}
className="text-sm text-notice opacity-80 hover:opacity-100"
> >
Learn More Learn More
</Link> </Link>
</p> </div>
</div> </p>
</div> </Banner>
)} ) : check.data?.type === 'personal_use' ? (
<Banner color="notice" className="@container flex items-center gap-x-5 max-w-xl">
<LocalImage src="static/greg.jpeg" className="hidden @sm:block rounded-full h-14 w-14" />
<p className="w-full">
Your commercial-use trial has ended.
<br />
<span className="opacity-50">
You can continue using Yaak for personal use free, forever.
<br />
A license is required for commercial use.
</span>
<Separator className="my-2" />
<div className="flex flex-wrap items-center gap-x-2 text-sm text-notice">
<Link noUnderline href="mailto:support@yaak.app">
Contact Support
</Link>
<Icon icon="dot" size="sm" color="secondary" />
<Link
noUnderline
href={`https://yaak.app/pricing?s=learn&t=${check.data?.type ?? ''}`}
>
Learn More
</Link>
</div>
</p>
</Banner>
) : null}
{check.error && <Banner color="danger">{check.error}</Banner>} {check.error && <Banner color="danger">{check.error}</Banner>}
{activate.error && <Banner color="danger">{activate.error}</Banner>} {activate.error && <Banner color="danger">{activate.error}</Banner>}

View File

@@ -12,32 +12,37 @@ interface Props extends HTMLAttributes<HTMLAnchorElement> {
export function Link({ href, children, noUnderline, className, ...other }: Props) { export function Link({ href, children, noUnderline, className, ...other }: Props) {
const isExternal = href.match(/^https?:\/\//); const isExternal = href.match(/^https?:\/\//);
className = classNames(className, 'relative'); className = classNames(
className,
'relative',
'inline-flex items-center hover:underline group',
!noUnderline && 'underline',
);
if (isExternal) { if (isExternal) {
const isYaakLink = href.startsWith('https://yaak.app');
let finalHref = href; let finalHref = href;
if (href.startsWith('https://yaak.app')) { if (isYaakLink) {
const url = new URL(href); const url = new URL(href);
url.searchParams.set('ref', appInfo.identifier); url.searchParams.set('ref', appInfo.identifier);
finalHref = url.toString(); finalHref = url.toString();
} }
return ( return (
// eslint-disable-next-line react/jsx-no-target-blank
<a <a
href={finalHref} href={finalHref}
target="_blank" target="_blank"
rel="noopener noreferrer" rel={isYaakLink ? undefined : 'noopener noreferrer'}
className={classNames( onClick={(e) => e.preventDefault()}
className, className={className}
'pr-4 inline-flex items-center hover:underline group',
!noUnderline && 'underline',
)}
onClick={(e) => {
e.preventDefault();
}}
{...other} {...other}
> >
<span className="pr-0.5">{children}</span> <span className="pr-5">{children}</span>
<Icon className="inline absolute right-0.5 top-[0.3em] opacity-70 group-hover:opacity-100" size="xs" icon="external_link" /> <Icon
className="inline absolute right-0.5 top-[0.3em] opacity-70 group-hover:opacity-100"
size="xs"
icon="external_link"
/>
</a> </a>
); );
} }

View File

@@ -1,3 +1,4 @@
import type { Color } from '@yaakapp-internal/plugins';
import classNames from 'classnames'; import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
@@ -6,9 +7,10 @@ interface Props {
dashed?: boolean; dashed?: boolean;
className?: string; className?: string;
children?: ReactNode; children?: ReactNode;
color?: Color;
} }
export function Separator({ className, dashed, orientation = 'horizontal', children }: Props) { export function Separator({ color, className, dashed, orientation = 'horizontal', children }: Props) {
return ( return (
<div role="separator" className={classNames(className, 'flex items-center w-full')}> <div role="separator" className={classNames(className, 'flex items-center w-full')}>
{children && ( {children && (
@@ -16,7 +18,15 @@ export function Separator({ className, dashed, orientation = 'horizontal', child
)} )}
<div <div
className={classNames( className={classNames(
'h-0 border-t border-t-border-subtle', 'h-0 border-t opacity-60',
color == null && 'border-border',
color === 'primary' && 'border-primary',
color === 'secondary' && 'border-secondary',
color === 'success' && 'border-success',
color === 'notice' && 'border-notice',
color === 'warning' && 'border-warning',
color === 'danger' && 'border-danger',
color === 'info' && 'border-info',
dashed && 'border-dashed', dashed && 'border-dashed',
orientation === 'horizontal' && 'w-full h-[1px]', orientation === 'horizontal' && 'w-full h-[1px]',
orientation === 'vertical' && 'h-full w-[1px]', orientation === 'vertical' && 'h-full w-[1px]',

View File

@@ -94,8 +94,8 @@ export function Tooltip({ children, content, tabIndex, size = 'md' }: TooltipPro
ref={triggerRef} ref={triggerRef}
role="button" role="button"
aria-describedby={isOpen ? id.current : undefined} aria-describedby={isOpen ? id.current : undefined}
tabIndex={tabIndex ?? 0} tabIndex={tabIndex ?? -1}
className="flex-grow-0 flex items-center" className="flex-grow-0 inline-flex items-center"
onClick={handleToggleImmediate} onClick={handleToggleImmediate}
onMouseEnter={handleOpen} onMouseEnter={handleOpen}
onMouseLeave={handleClose} onMouseLeave={handleClose}