mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-24 18:12:48 +03:00
Refactor button styles and update usage
This commit refactors the button component styles by introducing a new `kind` prop to replace the `filled` and `outlined` props. The `kind` prop takes values "filled", "outlined", or "plain". It also updates the usage of the button component in other components, using the new `kind` prop. Additionally, the button stories have been updated to remove redundancy and use the new `kind` prop. Changes: - Introduce `kind` prop in Button component - Remove `filled` and `outlined` props - Update button usage in BackForwardButtons and Breadcrumbs components - Update Button.stories to use new `kind` prop
This commit is contained in:
parent
5dd48b69ab
commit
2969c24dfa
@ -44,11 +44,6 @@
|
||||
</script>
|
||||
|
||||
<div class="flex items-center justify-center space-x-3 text-zinc-600">
|
||||
<Button filled={false} on:click={onBackClicked} disabled={!canGoBack} icon={IconArrowLeft} />
|
||||
<Button
|
||||
filled={false}
|
||||
on:click={onForwardClicked}
|
||||
icon={IconArrowRight}
|
||||
disabled={!canGoForward}
|
||||
/>
|
||||
<Button kind="plain" on:click={onBackClicked} disabled={!canGoBack} icon={IconArrowLeft} />
|
||||
<Button kind="plain" on:click={onForwardClicked} icon={IconArrowRight} disabled={!canGoForward} />
|
||||
</div>
|
||||
|
@ -8,10 +8,10 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row items-center gap-1 text-zinc-400">
|
||||
<Button icon={IconHome} filled={false} on:click={() => goto('/')} />
|
||||
<Button icon={IconHome} kind="plain" on:click={() => goto('/')} />
|
||||
{#if project}
|
||||
<Tooltip label="{project.title} home">
|
||||
<Button filled={false} on:click={() => project && goto(`/projects/${project.id}`)}>
|
||||
<Button kind="plain" on:click={() => project && goto(`/projects/${project.id}`)}>
|
||||
{project.title}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
@ -5,6 +5,7 @@
|
||||
import Button from './Button.svelte';
|
||||
|
||||
const heights = ['basic', 'small'] as const;
|
||||
const kinds = ['filled', 'outlined', 'plain'] as const;
|
||||
</script>
|
||||
|
||||
<Meta title="GitButler/Button" component={Button} />
|
||||
@ -13,16 +14,14 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each heights as height}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each [true, false] as filled}
|
||||
{#each [true, false] as outlined}
|
||||
{#each kinds as kind}
|
||||
<div class="flex gap-2">
|
||||
{#each [false, true] as loading}
|
||||
{#each [false, true] as disabled}
|
||||
<Button
|
||||
role="basic"
|
||||
{filled}
|
||||
color="basic"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
on:click={() => alert('Clicked!')}
|
||||
@ -30,10 +29,9 @@
|
||||
Button
|
||||
</Button>
|
||||
<Button
|
||||
role="basic"
|
||||
{filled}
|
||||
color="basic"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -42,10 +40,9 @@
|
||||
Button with icon
|
||||
</Button>
|
||||
<Button
|
||||
role="basic"
|
||||
{filled}
|
||||
color="basic"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -55,7 +52,6 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@ -65,16 +61,14 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each heights as height}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each [true, false] as filled}
|
||||
{#each [true, false] as outlined}
|
||||
{#each kinds as kind}
|
||||
<div class="flex gap-2">
|
||||
{#each [false, true] as loading}
|
||||
{#each [false, true] as disabled}
|
||||
<Button
|
||||
role="primary"
|
||||
{filled}
|
||||
color="primary"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
on:click={() => alert('Clicked!')}
|
||||
@ -82,10 +76,9 @@
|
||||
Button
|
||||
</Button>
|
||||
<Button
|
||||
role="primary"
|
||||
{filled}
|
||||
color="primary"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -94,10 +87,9 @@
|
||||
Button with icon
|
||||
</Button>
|
||||
<Button
|
||||
role="primary"
|
||||
{filled}
|
||||
color="primary"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -107,7 +99,6 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@ -117,16 +108,14 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each heights as height}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each [true, false] as filled}
|
||||
{#each [true, false] as outlined}
|
||||
{#each kinds as kind}
|
||||
<div class="flex gap-2">
|
||||
{#each [false, true] as loading}
|
||||
{#each [false, true] as disabled}
|
||||
<Button
|
||||
role="destructive"
|
||||
{filled}
|
||||
color="destructive"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
on:click={() => alert('Clicked!')}
|
||||
@ -134,10 +123,9 @@
|
||||
Button
|
||||
</Button>
|
||||
<Button
|
||||
role="destructive"
|
||||
{filled}
|
||||
color="destructive"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -146,10 +134,9 @@
|
||||
Button with icon
|
||||
</Button>
|
||||
<Button
|
||||
role="destructive"
|
||||
{filled}
|
||||
color="destructive"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -159,7 +146,6 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@ -169,16 +155,14 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
{#each heights as height}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each [true, false] as filled}
|
||||
{#each [true, false] as outlined}
|
||||
{#each kinds as kind}
|
||||
<div class="flex gap-2">
|
||||
{#each [false, true] as loading}
|
||||
{#each [false, true] as disabled}
|
||||
<Button
|
||||
role="purple"
|
||||
{filled}
|
||||
color="purple"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
on:click={() => alert('Clicked!')}
|
||||
@ -186,10 +170,9 @@
|
||||
Button
|
||||
</Button>
|
||||
<Button
|
||||
role="purple"
|
||||
{filled}
|
||||
color="purple"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -198,10 +181,9 @@
|
||||
Button with icon
|
||||
</Button>
|
||||
<Button
|
||||
role="purple"
|
||||
{filled}
|
||||
color="purple"
|
||||
{disabled}
|
||||
{outlined}
|
||||
{kind}
|
||||
{height}
|
||||
{loading}
|
||||
icon={IconHome}
|
||||
@ -211,7 +193,6 @@
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
{/each}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -2,9 +2,8 @@
|
||||
import { onMount, type ComponentType } from 'svelte';
|
||||
import { IconLoading } from '../icons';
|
||||
|
||||
export let role: 'basic' | 'primary' | 'destructive' | 'purple' = 'basic';
|
||||
export let filled = true;
|
||||
export let outlined = false;
|
||||
export let color: 'basic' | 'primary' | 'destructive' | 'purple' = 'basic';
|
||||
export let kind: 'plain' | 'filled' | 'outlined' = 'filled';
|
||||
export let disabled = false;
|
||||
export let height: 'basic' | 'small' = 'basic';
|
||||
export let width: 'basic' | 'full-width' = 'basic';
|
||||
@ -12,6 +11,9 @@
|
||||
export let icon: ComponentType | undefined = undefined;
|
||||
export let loading = false;
|
||||
|
||||
let filled = kind === 'filled';
|
||||
let outlined = kind === 'outlined';
|
||||
|
||||
let element: HTMLAnchorElement | HTMLButtonElement;
|
||||
|
||||
onMount(() => {
|
||||
@ -20,7 +22,7 @@
|
||||
</script>
|
||||
|
||||
<button
|
||||
class={role}
|
||||
class={color}
|
||||
class:small={height === 'small'}
|
||||
class:full-width={width === 'full-width'}
|
||||
class:pointer-events-none={loading}
|
||||
@ -54,7 +56,7 @@
|
||||
|
||||
<style lang="postcss">
|
||||
button {
|
||||
@apply relative flex h-[36px] w-fit cursor-pointer items-center justify-center gap-[10px] whitespace-nowrap rounded py-2 text-base font-medium transition transition duration-150 ease-in-out ease-out hover:ease-in;
|
||||
@apply relative flex h-[36px] w-fit cursor-pointer items-center justify-center gap-[10px] whitespace-nowrap rounded py-2 text-base font-medium underline transition transition duration-150 ease-in-out ease-out hover:ease-in;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
@ -65,70 +67,85 @@
|
||||
@apply text-zinc-300;
|
||||
}
|
||||
.basic:hover {
|
||||
@apply bg-[#D4D4D8]/20;
|
||||
@apply bg-[#D4D4D833]/20 no-underline;
|
||||
}
|
||||
.basic:active {
|
||||
@apply bg-transparent no-underline;
|
||||
}
|
||||
.basic.outlined {
|
||||
@apply border-zinc-500;
|
||||
@apply border-[#3F3F46] no-underline;
|
||||
}
|
||||
.basic.outlined:hover {
|
||||
@apply bg-[#FFFFFF1A]/10;
|
||||
@apply bg-[#3F3F46]/20;
|
||||
}
|
||||
.basic.filled {
|
||||
@apply bg-zinc-500;
|
||||
@apply bg-[#3F3F46] no-underline;
|
||||
}
|
||||
.basic.filled:hover {
|
||||
@apply bg-zinc-600;
|
||||
@apply bg-[#35353B];
|
||||
}
|
||||
|
||||
.primary {
|
||||
@apply text-blue-500;
|
||||
}
|
||||
.primary:hover {
|
||||
@apply bg-[#3B82F6]/20;
|
||||
@apply bg-[#3B82F6]/20 no-underline;
|
||||
}
|
||||
.primary:disabled {
|
||||
@apply text-[#BDC1CC] no-underline opacity-100;
|
||||
}
|
||||
.primary:active {
|
||||
@apply bg-transparent text-blue-700 underline;
|
||||
}
|
||||
.primary.outlined {
|
||||
@apply border-[#3662E3];
|
||||
@apply border-[#3662E3] no-underline;
|
||||
}
|
||||
.primary.outlined:hover {
|
||||
@apply bg-[#1C48C94D]/20;
|
||||
}
|
||||
.primary.filled {
|
||||
@apply bg-blue-600;
|
||||
@apply bg-blue-600 no-underline;
|
||||
}
|
||||
.primary.filled:hover {
|
||||
@apply bg-[#1C48C9];
|
||||
}
|
||||
|
||||
.destructive {
|
||||
@apply text-red-600;
|
||||
@apply text-red-600 no-underline;
|
||||
}
|
||||
.destructive:hover {
|
||||
@apply bg-[#DC2626]/20;
|
||||
}
|
||||
.destructive.outlined {
|
||||
@apply border-[#E33636];
|
||||
}
|
||||
.destructive.outlined:hover {
|
||||
@apply bg-[#E336364D]/30;
|
||||
.destructive:active {
|
||||
@apply bg-transparent text-red-400;
|
||||
}
|
||||
.destructive.filled {
|
||||
@apply bg-[#E33636];
|
||||
@apply bg-[#BF4545] text-zinc-50 no-underline;
|
||||
}
|
||||
.destructive.filled:disabled {
|
||||
@apply bg-[#EB2525];
|
||||
}
|
||||
.destructive.filled:hover {
|
||||
@apply bg-[#C91C1C];
|
||||
}
|
||||
.destructive.outlined {
|
||||
@apply border-[#BF4545] text-[#BF4545] no-underline;
|
||||
}
|
||||
.destructive.outlined:hover {
|
||||
@apply bg-[#E3363633]/20;
|
||||
}
|
||||
|
||||
.purple {
|
||||
@apply text-[#5852A0];
|
||||
}
|
||||
.purple.outlined {
|
||||
@apply border-[#524C93];
|
||||
@apply border-[#524C93] no-underline;
|
||||
}
|
||||
.purple.outlined:hover {
|
||||
@apply bg-[#524C93]/20;
|
||||
}
|
||||
.purple.filled {
|
||||
@apply bg-[#5852A0];
|
||||
@apply bg-[#5852A0] no-underline;
|
||||
}
|
||||
.purple.filled:hover {
|
||||
@apply bg-[#423E7A];
|
||||
|
@ -15,7 +15,7 @@
|
||||
<Button on:click={leftAction} {width}>
|
||||
{leftLabel}
|
||||
</Button>
|
||||
<Button on:click={rightAction} role="primary" {width}>
|
||||
<Button on:click={rightAction} color="primary" {width}>
|
||||
{rightLabel}
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
||||
<slot name="title">Title</slot>
|
||||
</h2>
|
||||
|
||||
<Button filled={false} on:click={close} icon={IconClose} />
|
||||
<Button kind="plain" on:click={close} icon={IconClose} />
|
||||
</header>
|
||||
|
||||
{#if $$slots.default}
|
||||
@ -27,8 +27,8 @@
|
||||
|
||||
<footer class="flex w-full justify-end gap-4 p-4">
|
||||
<slot name="controls" {close}>
|
||||
<Button filled={false} outlined={true} on:click={close}>Secondary action</Button>
|
||||
<Button role="primary" on:click={close}>Primary action</Button>
|
||||
<Button kind="outlined" on:click={close}>Secondary action</Button>
|
||||
<Button color="primary" on:click={close}>Primary action</Button>
|
||||
</slot>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -3,7 +3,6 @@
|
||||
import { Status, type Project, git } from '$lib/api';
|
||||
import type { CloudApi, User } from '$lib/api';
|
||||
import { Button, Modal, Link } from '$lib/components';
|
||||
import Tooltip from './Tooltip/Tooltip.svelte';
|
||||
import { IconGitBranch, IconSparkle } from './icons';
|
||||
|
||||
export const show = () => modal.show();
|
||||
@ -151,9 +150,8 @@
|
||||
/>
|
||||
|
||||
<Button
|
||||
role="purple"
|
||||
filled={false}
|
||||
outlined={true}
|
||||
color="purple"
|
||||
kind="outlined"
|
||||
disabled={isCommitting || !project.api?.sync}
|
||||
loading={isAutowriting}
|
||||
on:click={onAutowrite}
|
||||
@ -202,8 +200,8 @@
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<Button filled={false} outlined={true} on:click={close}>Cancel</Button>
|
||||
<Button type="submit" disabled={isAutowriting} role="primary" loading={isCommitting}>
|
||||
<Button kind="outlined" on:click={close}>Cancel</Button>
|
||||
<Button type="submit" disabled={isAutowriting} color="primary" loading={isCommitting}>
|
||||
Commit
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -142,7 +142,7 @@
|
||||
<h3 class="mt-2 text-lg font-semibold text-zinc-300">No projects</h3>
|
||||
<p class="mt-1 text-gray-500">Get started by tracking a project you're working on.</p>
|
||||
<div class="mt-6">
|
||||
<Button role="primary" on:click={onAddLocalRepositoryClick}>
|
||||
<Button color="primary" on:click={onAddLocalRepositoryClick}>
|
||||
Start Tracking a Project
|
||||
</Button>
|
||||
</div>
|
||||
@ -160,7 +160,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<Tooltip label="Adds a git repository on your computer to GitButler">
|
||||
<Button role="primary" on:click={onAddLocalRepositoryClick}>
|
||||
<Button color="primary" on:click={onAddLocalRepositoryClick}>
|
||||
Track a New Project
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
@ -94,7 +94,7 @@
|
||||
<Tooltip label="Terminal">
|
||||
<Button
|
||||
on:click={() => goto(`/projects/${$project.id}/terminal`)}
|
||||
filled={false}
|
||||
kind="plain"
|
||||
height="small"
|
||||
icon={IconTerminal}
|
||||
/>
|
||||
@ -104,7 +104,7 @@
|
||||
<Tooltip label="Project settings">
|
||||
<Button
|
||||
on:click={() => goto(`/projects/${$project.id}/settings`)}
|
||||
filled={false}
|
||||
kind="plain"
|
||||
height="small"
|
||||
icon={IconSettings}
|
||||
/>
|
||||
|
@ -81,11 +81,11 @@
|
||||
</div>
|
||||
</Tooltip>
|
||||
{#await statuses.load()}
|
||||
<Button disabled role="primary">Commit changes</Button>
|
||||
<Button disabled color="primary">Commit changes</Button>
|
||||
{:then}
|
||||
<Button
|
||||
disabled={Object.keys($statuses).length === 0}
|
||||
role="primary"
|
||||
color="primary"
|
||||
on:click={() => goto(`/projects/${$project?.id}/commit`)}
|
||||
>
|
||||
Commit changes
|
||||
|
@ -137,7 +137,7 @@
|
||||
<div class="flex gap-2 text-xl">Chat GitButler</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<Button role="basic" height="small" on:click={setupChat}>Reset chat</Button>
|
||||
<Button color="basic" height="small" on:click={setupChat}>Reset chat</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -282,7 +282,7 @@
|
||||
/>
|
||||
<Button
|
||||
disabled={chatInput.length == 0 || !chatId}
|
||||
role="primary"
|
||||
color="primary"
|
||||
on:click={() => {
|
||||
newChatMessage(chatId, chatInput).then((data) => {
|
||||
requestedSeq = +data;
|
||||
@ -303,7 +303,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
<style lang="postcss">
|
||||
.chat-user-avatar {
|
||||
@apply relative flex h-[40px] w-[40px] items-center justify-center rounded-full p-2;
|
||||
}
|
||||
|
@ -237,8 +237,8 @@
|
||||
</p>
|
||||
</div>
|
||||
<svelte:fragment slot="controls" let:close>
|
||||
<Button filled={false} outlined={true} on:click={close}>Cancel</Button>
|
||||
<Button role="primary" on:click={() => enableProjectSync().finally(close)}>Connect</Button>
|
||||
<Button kind="outlined" on:click={close}>Cancel</Button>
|
||||
<Button color="primary" on:click={() => enableProjectSync().finally(close)}>Connect</Button>
|
||||
</svelte:fragment>
|
||||
</Dialog>
|
||||
|
||||
@ -366,7 +366,7 @@
|
||||
|
||||
<div class="flex justify-between">
|
||||
<Button
|
||||
role="purple"
|
||||
color="purple"
|
||||
disabled={!isGenerateCommitEnabled}
|
||||
on:click={onGenerateCommitMessage}
|
||||
loading={isGeneratingCommitMessage}
|
||||
@ -377,7 +377,7 @@
|
||||
<Button
|
||||
loading={isCommitting}
|
||||
disabled={!isCommitEnabled || isGeneratingCommitMessage}
|
||||
role="primary"
|
||||
color="primary"
|
||||
type="submit"
|
||||
>
|
||||
Commit changes
|
||||
|
@ -218,11 +218,15 @@
|
||||
</fieldset>
|
||||
|
||||
<footer class="flex justify-between">
|
||||
<Button role="destructive" filled={false} on:click={() => deleteConfirmationDialog.show()}
|
||||
>Delete project</Button
|
||||
<Button
|
||||
color="destructive"
|
||||
kind="outlined"
|
||||
on:click={() => deleteConfirmationDialog.show()}
|
||||
>
|
||||
Delete project
|
||||
</Button>
|
||||
|
||||
<Button disabled={!canTriggerUpdate} loading={saving} role="primary" type="submit">
|
||||
<Button disabled={!canTriggerUpdate} loading={saving} color="primary" type="submit">
|
||||
Update project
|
||||
</Button>
|
||||
</footer>
|
||||
@ -238,13 +242,13 @@
|
||||
|
||||
<p>
|
||||
Are you sure you want to delete the project,
|
||||
<span class="font-bold text-white">hugo-ianthedesigner</span>? This can’t be undone.
|
||||
<span class="font-bold text-white">{$project.title}</span>? This can’t be undone.
|
||||
</p>
|
||||
|
||||
<svelte:fragment slot="controls" let:close>
|
||||
<Button filled={false} outlined={true} on:click={close}>Cancel</Button>
|
||||
<Button role="destructive" loading={isDeleting} on:click={onDeleteClicked}
|
||||
>Delete project</Button
|
||||
>
|
||||
<Button kind="outlined" on:click={close}>Cancel</Button>
|
||||
<Button color="destructive" loading={isDeleting} on:click={onDeleteClicked}>
|
||||
Delete project
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
</Dialog>
|
||||
|
@ -39,7 +39,7 @@
|
||||
{/await}
|
||||
<div class="mt-4 font-bold">Commands</div>
|
||||
<ul class="py-2">
|
||||
<Button role="primary" width="full-width" on:click={() => runCommand('git push')}>
|
||||
<Button color="primary" width="full-width" on:click={() => runCommand('git push')}>
|
||||
Push Commit
|
||||
</Button>
|
||||
</ul>
|
||||
|
@ -138,9 +138,9 @@
|
||||
</div>
|
||||
|
||||
<footer class="flex justify-end pt-4">
|
||||
<Button disabled={!canTriggerUpdate} loading={saving} role="primary" type="submit"
|
||||
>Update profile</Button
|
||||
>
|
||||
<Button disabled={!canTriggerUpdate} loading={saving} color="primary" type="submit">
|
||||
Update profile
|
||||
</Button>
|
||||
</footer>
|
||||
</fields>
|
||||
</form>
|
||||
|
@ -60,6 +60,7 @@ const config = {
|
||||
900: '#713f12'
|
||||
},
|
||||
red: {
|
||||
400: '#F87171',
|
||||
500: '#ef4444',
|
||||
600: '#dc2626',
|
||||
700: '#b91c1c',
|
||||
|
Loading…
Reference in New Issue
Block a user