Compare commits
1 Commits
main
...
claude/mob
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f2eda521f |
41
apps/web/e2e/mobile-font-size.spec.ts
Normal file
41
apps/web/e2e/mobile-font-size.spec.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { expect, type Locator, test } from "@playwright/test";
|
||||||
|
import { captureScreenshot, completeOnboarding, signup } from "./helpers";
|
||||||
|
|
||||||
|
async function fontSize(locator: Locator) {
|
||||||
|
return locator.evaluate((element) => Number.parseFloat(getComputedStyle(element).fontSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
test("phone widths read text at 16px and up while desktop keeps its sizes", async ({
|
||||||
|
page,
|
||||||
|
}, testInfo) => {
|
||||||
|
const stamp = Date.now();
|
||||||
|
await signup(page, `mobile-font-${stamp}@rakazo.test`, "password12", "Font QA");
|
||||||
|
await completeOnboarding(page);
|
||||||
|
|
||||||
|
const composer = page.getByRole("combobox", { name: /^Message/ });
|
||||||
|
await composer.fill("Please review `shared/PROJECT_CHECKPOINT_WRAPUP.md`.");
|
||||||
|
await composer.press("Enter");
|
||||||
|
const reply = page
|
||||||
|
.getByTestId("transcript")
|
||||||
|
.locator("[data-message-id]")
|
||||||
|
.filter({ hasText: "done. i handled:" });
|
||||||
|
await expect(reply).toBeVisible({ timeout: 30_000 });
|
||||||
|
|
||||||
|
const smallText = page.locator(".text-ui-body-sm").first();
|
||||||
|
const desktopSmall = await fontSize(smallText);
|
||||||
|
expect(desktopSmall).toBe(14);
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 390, height: 844 });
|
||||||
|
await expect.poll(() => fontSize(smallText)).toBeCloseTo(16, 1);
|
||||||
|
expect(await fontSize(composer)).toBeGreaterThanOrEqual(16);
|
||||||
|
|
||||||
|
await page.emulateMedia({ colorScheme: "dark" });
|
||||||
|
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||||
|
await captureScreenshot(page, testInfo, "mobile-font-size-dark");
|
||||||
|
await page.emulateMedia({ colorScheme: "light" });
|
||||||
|
await expect(page.locator("html")).toHaveAttribute("data-theme", "light");
|
||||||
|
await captureScreenshot(page, testInfo, "mobile-font-size-light");
|
||||||
|
|
||||||
|
await page.setViewportSize({ width: 1280, height: 720 });
|
||||||
|
await expect.poll(() => fontSize(smallText)).toBe(desktopSmall);
|
||||||
|
});
|
||||||
@ -251,7 +251,7 @@ export function OoStage({
|
|||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-1 max-w-xl truncate text-center text-ui-caption text-muted-foreground">
|
<p className="mt-1 w-full max-w-xl truncate text-center text-ui-caption text-muted-foreground">
|
||||||
{subtitle}
|
{subtitle}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@ -548,7 +548,7 @@ export function OoGroupStage({
|
|||||||
{subtitle}
|
{subtitle}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p className="mt-1 max-w-xl truncate text-center text-ui-caption text-muted-foreground">
|
<p className="mt-1 w-full max-w-xl truncate text-center text-ui-caption text-muted-foreground">
|
||||||
{subtitle}
|
{subtitle}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -80,7 +80,10 @@ export function ExternalConversationSettings({
|
|||||||
return (
|
return (
|
||||||
<div data-testid="external-conversation-settings">
|
<div data-testid="external-conversation-settings">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h2 className="truncate text-[17px] font-medium text-foreground" dir="auto">
|
<h2
|
||||||
|
className="truncate text-ui-reading leading-normal font-medium text-foreground"
|
||||||
|
dir="auto"
|
||||||
|
>
|
||||||
{conversation.displayName || t`External conversation`}
|
{conversation.displayName || t`External conversation`}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="mt-1 truncate text-ui-body-sm text-muted-foreground">
|
<p className="mt-1 truncate text-ui-body-sm text-muted-foreground">
|
||||||
|
|||||||
@ -134,7 +134,7 @@ export function PeerMessagesOverlay({
|
|||||||
<div className="mb-1 text-ui-body-sm text-muted-foreground/70" dir="auto">
|
<div className="mb-1 text-ui-body-sm text-muted-foreground/70" dir="auto">
|
||||||
{sent ? botName : peerBotName}
|
{sent ? botName : peerBotName}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-[14.5px] leading-[1.5] text-foreground/90" dir="auto">
|
<div className="text-ui-body-sm leading-[1.5] text-foreground/90" dir="auto">
|
||||||
<ChatMarkdown>{peerMessage.text}</ChatMarkdown>
|
<ChatMarkdown>{peerMessage.text}</ChatMarkdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -558,7 +558,9 @@ export function PluginsOverlay({
|
|||||||
{item.name[0]}
|
{item.name[0]}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="truncate text-[17px] font-medium text-foreground">{item.name}</div>
|
<div className="truncate text-ui-reading leading-normal font-medium text-foreground">
|
||||||
|
{item.name}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -156,7 +156,7 @@ export function RoutineListRow({
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span className="min-w-0 flex-1">
|
<span className="min-w-0 flex-1">
|
||||||
<span className="block truncate text-[14.5px] font-medium text-foreground" dir="auto">
|
<span className="block truncate text-ui-body-sm font-medium text-foreground" dir="auto">
|
||||||
{routineName(routine)}
|
{routineName(routine)}
|
||||||
</span>
|
</span>
|
||||||
<span className="block truncate text-ui-body-sm text-muted-foreground/80">
|
<span className="block truncate text-ui-body-sm text-muted-foreground/80">
|
||||||
@ -522,7 +522,7 @@ function MessageTriggerCard({ provider, onRemove }: { provider: string; onRemove
|
|||||||
className="text-muted-foreground size-icon-md"
|
className="text-muted-foreground size-icon-md"
|
||||||
aria-hidden
|
aria-hidden
|
||||||
/>
|
/>
|
||||||
<span className="flex-1 text-[14.5px] text-foreground">{label}</span>
|
<span className="flex-1 text-ui-body-sm text-foreground">{label}</span>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon-xs"
|
size="icon-xs"
|
||||||
@ -587,7 +587,7 @@ function InboundTriggerCard({
|
|||||||
) : (
|
) : (
|
||||||
<Globe strokeWidth={1.6} className="text-muted-foreground size-icon-md" aria-hidden />
|
<Globe strokeWidth={1.6} className="text-muted-foreground size-icon-md" aria-hidden />
|
||||||
)}
|
)}
|
||||||
<span className="flex-1 text-[14.5px] text-foreground">
|
<span className="flex-1 text-ui-body-sm text-foreground">
|
||||||
{kind === "github" ? <Trans>Git event</Trans> : <Trans>When a webhook fires</Trans>}
|
{kind === "github" ? <Trans>Git event</Trans> : <Trans>When a webhook fires</Trans>}
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -229,9 +229,9 @@ export function RoutineSchedule({
|
|||||||
<div className="mt-2 rounded-xl border border-border p-3">
|
<div className="mt-2 rounded-xl border border-border p-3">
|
||||||
<div className="flex items-center gap-2.5 px-0.5">
|
<div className="flex items-center gap-2.5 px-0.5">
|
||||||
<Clock size={17} strokeWidth={1.6} className="shrink-0 text-muted-foreground" aria-hidden />
|
<Clock size={17} strokeWidth={1.6} className="shrink-0 text-muted-foreground" aria-hidden />
|
||||||
<span className="text-[14.5px] text-foreground">{lead}</span>
|
<span className="text-ui-body-sm text-foreground">{lead}</span>
|
||||||
{detail ? (
|
{detail ? (
|
||||||
<span className="flex-1 text-[14.5px] text-muted-foreground">{detail}</span>
|
<span className="flex-1 text-ui-body-sm text-muted-foreground">{detail}</span>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2.5 flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
|
<div className="mt-2.5 flex flex-wrap items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
|||||||
@ -124,7 +124,7 @@ export function ScratchpadSection({ botId }: { botId: string }) {
|
|||||||
/>
|
/>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div
|
<div
|
||||||
className={`text-start text-[14.5px] ${item.status === "done" ? "text-muted-foreground/80 line-through" : "text-foreground"}`}
|
className={`text-start text-ui-body-sm ${item.status === "done" ? "text-muted-foreground/80 line-through" : "text-foreground"}`}
|
||||||
dir="auto"
|
dir="auto"
|
||||||
>
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ export function WelcomePage() {
|
|||||||
<p className="text-[27px] leading-[1.35] text-foreground/90 font-medium">
|
<p className="text-[27px] leading-[1.35] text-foreground/90 font-medium">
|
||||||
<Trans>Your specialists. One calm place to talk.</Trans>
|
<Trans>Your specialists. One calm place to talk.</Trans>
|
||||||
</p>
|
</p>
|
||||||
<p className="text-[18px] leading-[1.5] text-foreground/60">
|
<p className="text-ui-title-sm leading-[1.5] text-foreground/60">
|
||||||
<Trans>Simple to start. Expert when you need it.</Trans>
|
<Trans>Simple to start. Expert when you need it.</Trans>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -383,7 +383,7 @@ function ChartCanvas({
|
|||||||
return (
|
return (
|
||||||
<div className="text-foreground/75">
|
<div className="text-foreground/75">
|
||||||
{meta.title ? (
|
{meta.title ? (
|
||||||
<div className="mb-1 text-[14.5px] font-semibold text-foreground">{meta.title}</div>
|
<div className="mb-1 text-ui-body-sm font-semibold text-foreground">{meta.title}</div>
|
||||||
) : null}
|
) : null}
|
||||||
{meta.swatches.length > 0 ? (
|
{meta.swatches.length > 0 ? (
|
||||||
<div className="mb-2 flex flex-wrap gap-x-3 gap-y-1">
|
<div className="mb-2 flex flex-wrap gap-x-3 gap-y-1">
|
||||||
@ -460,7 +460,7 @@ export function McpApprovalCard({
|
|||||||
<span className="grid size-control-sm place-items-center rounded-lg bg-muted text-ui-label text-foreground">
|
<span className="grid size-control-sm place-items-center rounded-lg bg-muted text-ui-label text-foreground">
|
||||||
M
|
M
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[14.5px] font-medium text-foreground">
|
<span className="text-ui-body-sm font-medium text-foreground">
|
||||||
<Trans>Connect MCP server “{name}”</Trans>
|
<Trans>Connect MCP server “{name}”</Trans>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -811,7 +811,7 @@ const MessageView = memo(function MessageView({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span
|
<span
|
||||||
className="text-[14.5px] font-semibold text-foreground tracking-tight"
|
className="text-ui-body-sm font-semibold text-foreground tracking-tight"
|
||||||
dir="auto"
|
dir="auto"
|
||||||
>
|
>
|
||||||
{effectiveSpeakerName}
|
{effectiveSpeakerName}
|
||||||
@ -1048,7 +1048,7 @@ const MessageView = memo(function MessageView({
|
|||||||
</div>
|
</div>
|
||||||
<div className="mt-2 text-ui-body text-muted-foreground">{block.task}</div>
|
<div className="mt-2 text-ui-body text-muted-foreground">{block.task}</div>
|
||||||
{block.progress || block.result ? (
|
{block.progress || block.result ? (
|
||||||
<div className="mt-2.5 text-[14.5px] leading-[1.5] text-foreground/75">
|
<div className="mt-2.5 text-ui-body-sm leading-[1.5] text-foreground/75">
|
||||||
<ChatMarkdown streaming={running}>
|
<ChatMarkdown streaming={running}>
|
||||||
{block.result || block.progress || ""}
|
{block.result || block.progress || ""}
|
||||||
</ChatMarkdown>
|
</ChatMarkdown>
|
||||||
@ -1095,7 +1095,7 @@ const MessageView = memo(function MessageView({
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 text-[14.5px] leading-[1.5] text-foreground/75" dir="auto">
|
<div className="mt-2 text-ui-body-sm leading-[1.5] text-foreground/75" dir="auto">
|
||||||
{removed
|
{removed
|
||||||
? block.status === "archived"
|
? block.status === "archived"
|
||||||
? t`Archived. Chat, memory, and files kept.`
|
? t`Archived. Chat, memory, and files kept.`
|
||||||
@ -1201,7 +1201,7 @@ const MessageView = memo(function MessageView({
|
|||||||
className={
|
className={
|
||||||
encounterMode
|
encounterMode
|
||||||
? "max-w-full whitespace-pre-wrap wrap-anywhere rounded-2xl bg-chat-user px-3.5 py-2 text-ui-body-sm leading-relaxed text-chat-user-foreground"
|
? "max-w-full whitespace-pre-wrap wrap-anywhere rounded-2xl bg-chat-user px-3.5 py-2 text-ui-body-sm leading-relaxed text-chat-user-foreground"
|
||||||
: "chat-bubble-user max-w-full whitespace-pre-wrap wrap-anywhere rounded-[24px] px-6 py-4 text-[17px] leading-[1.62] text-chat-user-foreground shadow-md"
|
: "chat-bubble-user max-w-full whitespace-pre-wrap wrap-anywhere rounded-[24px] px-6 py-4 text-ui-reading leading-[1.62] text-chat-user-foreground shadow-md"
|
||||||
}
|
}
|
||||||
dir="auto"
|
dir="auto"
|
||||||
>
|
>
|
||||||
@ -1218,7 +1218,7 @@ const MessageView = memo(function MessageView({
|
|||||||
className={
|
className={
|
||||||
encounterMode
|
encounterMode
|
||||||
? "max-w-full space-y-2 border-s-2 border-emerald-500/35 ps-3 text-ui-body-sm leading-relaxed text-foreground/90"
|
? "max-w-full space-y-2 border-s-2 border-emerald-500/35 ps-3 text-ui-body-sm leading-relaxed text-foreground/90"
|
||||||
: "chat-bubble-bot max-w-full space-y-3 rounded-[24px] px-6 py-4 text-[17.5px] leading-[1.85] text-foreground/95"
|
: "chat-bubble-bot max-w-full space-y-3 rounded-[24px] px-6 py-4 text-ui-reading leading-[1.85] text-foreground/95"
|
||||||
}
|
}
|
||||||
dir="auto"
|
dir="auto"
|
||||||
>
|
>
|
||||||
@ -1330,7 +1330,7 @@ const MessageView = memo(function MessageView({
|
|||||||
{block.state}
|
{block.state}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="my-2.5 text-[14.5px] leading-[1.5] text-foreground/75">
|
<div className="my-2.5 text-ui-body-sm leading-[1.5] text-foreground/75">
|
||||||
<ChatMarkdown>{block.text}</ChatMarkdown>
|
<ChatMarkdown>{block.text}</ChatMarkdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -30,7 +30,7 @@ export function UserMenu({
|
|||||||
<span className="grid size-control-lg place-items-center rounded-full bg-accent text-ui-body-sm text-foreground/75">
|
<span className="grid size-control-lg place-items-center rounded-full bg-accent text-ui-body-sm text-foreground/75">
|
||||||
{initials}
|
{initials}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[14.5px] text-foreground/90">{userName}</span>
|
<span className="text-ui-body-sm text-foreground/90">{userName}</span>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
{open ? (
|
{open ? (
|
||||||
<PopoverContent
|
<PopoverContent
|
||||||
|
|||||||
@ -98,7 +98,7 @@ body,
|
|||||||
/* Gemini-Grade Accessible Typography (Apple-like with Inter Variable).
|
/* Gemini-Grade Accessible Typography (Apple-like with Inter Variable).
|
||||||
Heading, code and quote colors come from the shared @rakazo/chat-ui markdown styles. */
|
Heading, code and quote colors come from the shared @rakazo/chat-ui markdown styles. */
|
||||||
.rk-chat-markdown {
|
.rk-chat-markdown {
|
||||||
font-size: var(--font-size-reading);
|
font-size: calc(var(--font-size-reading) * var(--font-scale));
|
||||||
line-height: var(--line-height-reading);
|
line-height: var(--line-height-reading);
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
letter-spacing: -0.011em;
|
letter-spacing: -0.011em;
|
||||||
@ -116,7 +116,7 @@ body,
|
|||||||
inset 0 1px 0 rgba(255, 255, 255, 0.09),
|
inset 0 1px 0 rgba(255, 255, 255, 0.09),
|
||||||
0 12px 36px rgba(0, 0, 0, 0.55);
|
0 12px 36px rgba(0, 0, 0, 0.55);
|
||||||
padding: 1.25em 1.5em;
|
padding: 1.25em 1.5em;
|
||||||
font-size: 14.5px;
|
font-size: calc(14.5px * var(--font-scale));
|
||||||
line-height: 1.65;
|
line-height: 1.65;
|
||||||
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
}
|
}
|
||||||
@ -130,7 +130,7 @@ body,
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 0.15em 0.4em;
|
padding: 0.15em 0.4em;
|
||||||
font-size: 14.5px;
|
font-size: calc(14.5px * var(--font-scale));
|
||||||
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
|
font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,20 +45,26 @@
|
|||||||
--radius-xl: calc(var(--radius) + 4px);
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
--radius-2xl: calc(var(--radius) + 8px);
|
--radius-2xl: calc(var(--radius) + 8px);
|
||||||
|
|
||||||
/* Typography scale */
|
/* Typography scale. Every text size follows --font-scale, which grows on phones. */
|
||||||
--text-ui-caption: var(--font-size-caption);
|
--text-xs: calc(0.75rem * var(--font-scale));
|
||||||
|
--text-sm: calc(0.875rem * var(--font-scale));
|
||||||
|
--text-base: calc(1rem * var(--font-scale));
|
||||||
|
--text-lg: calc(1.125rem * var(--font-scale));
|
||||||
|
--text-xl: calc(1.25rem * var(--font-scale));
|
||||||
|
--text-2xl: calc(1.5rem * var(--font-scale));
|
||||||
|
--text-ui-caption: calc(var(--font-size-caption) * var(--font-scale));
|
||||||
--text-ui-caption--line-height: var(--line-height-tight);
|
--text-ui-caption--line-height: var(--line-height-tight);
|
||||||
--text-ui-label: var(--font-size-label);
|
--text-ui-label: calc(var(--font-size-label) * var(--font-scale));
|
||||||
--text-ui-label--line-height: var(--line-height-tight);
|
--text-ui-label--line-height: var(--line-height-tight);
|
||||||
--text-ui-body-sm: var(--font-size-body-sm);
|
--text-ui-body-sm: calc(var(--font-size-body-sm) * var(--font-scale));
|
||||||
--text-ui-body-sm--line-height: var(--line-height-body);
|
--text-ui-body-sm--line-height: var(--line-height-body);
|
||||||
--text-ui-body: var(--font-size-body);
|
--text-ui-body: calc(var(--font-size-body) * var(--font-scale));
|
||||||
--text-ui-body--line-height: var(--line-height-body);
|
--text-ui-body--line-height: var(--line-height-body);
|
||||||
--text-ui-reading: var(--font-size-reading);
|
--text-ui-reading: calc(var(--font-size-reading) * var(--font-scale));
|
||||||
--text-ui-reading--line-height: var(--line-height-reading);
|
--text-ui-reading--line-height: var(--line-height-reading);
|
||||||
--text-ui-title-sm: var(--font-size-title-sm);
|
--text-ui-title-sm: calc(var(--font-size-title-sm) * var(--font-scale));
|
||||||
--text-ui-title-sm--line-height: var(--line-height-tight);
|
--text-ui-title-sm--line-height: var(--line-height-tight);
|
||||||
--text-ui-title: var(--font-size-title);
|
--text-ui-title: calc(var(--font-size-title) * var(--font-scale));
|
||||||
--text-ui-title--line-height: var(--line-height-tight);
|
--text-ui-title--line-height: var(--line-height-tight);
|
||||||
|
|
||||||
/* Control + icon sizes (also drive h-*, size-*, gap-*, p-* utilities) */
|
/* Control + icon sizes (also drive h-*, size-*, gap-*, p-* utilities) */
|
||||||
@ -74,6 +80,18 @@
|
|||||||
--spacing-rk-sidebar-y: var(--spacing-sidebar-row-y);
|
--spacing-rk-sidebar-y: var(--spacing-sidebar-row-y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Phones read the 14px base size at 16px (Safari also stops zooming into fields at 16px);
|
||||||
|
all other sizes grow by the same ratio. */
|
||||||
|
:root {
|
||||||
|
--font-scale: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
:root {
|
||||||
|
--font-scale: 1.142857;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user