fix: restore sidebar push-layout, fix default expanded state, and relocate add-torrent button
Some checks failed
Build MIPS Binary / build (push) Failing after 34s
Some checks failed
Build MIPS Binary / build (push) Failing after 34s
This commit is contained in:
@@ -79,16 +79,20 @@ pub fn Sidebar() -> impl IntoView {
|
||||
});
|
||||
};
|
||||
|
||||
let is_collapsed = move || store.sidenav_state.get() == crate::components::ui::sidenav::SidenavState::Collapsed;
|
||||
|
||||
view! {
|
||||
<SidenavHeader>
|
||||
<div class="flex items-center gap-2 px-2 py-4">
|
||||
<div class="flex size-8 items-center justify-center rounded-lg bg-primary text-primary-foreground shadow-sm">
|
||||
<div class="flex items-center gap-3 px-2 py-4">
|
||||
<div class="flex size-9 items-center justify-center rounded-lg bg-primary text-primary-foreground shadow-sm shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0112 21 8.25 8.25 0 016.038 7.048 8.287 8.287 0 009 9.6a8.983 8.983 0 013.361-6.867 8.21 8.25 0 003 2.48z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="grid flex-1 text-left text-sm leading-tight overflow-hidden">
|
||||
<span class="truncate font-semibold text-foreground text-base">"VibeTorrent"</span>
|
||||
<div class="grid flex-1 text-left text-sm leading-tight overflow-hidden transition-all duration-300"
|
||||
class:opacity-0=is_collapsed
|
||||
class:w-0=is_collapsed>
|
||||
<span class="truncate font-bold text-foreground text-base">"VibeTorrent"</span>
|
||||
<span class="truncate text-[10px] text-muted-foreground opacity-70">"v3.0.0"</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,7 +100,7 @@ pub fn Sidebar() -> impl IntoView {
|
||||
|
||||
<SidenavContent>
|
||||
<SidenavGroup>
|
||||
<SidenavGroupLabel>"Filtreler"</SidenavGroupLabel>
|
||||
<SidenavGroupLabel class:hidden=is_collapsed>"Filtreler"</SidenavGroupLabel>
|
||||
<SidenavGroupContent>
|
||||
<SidenavMenu>
|
||||
<SidebarItem
|
||||
@@ -105,54 +109,20 @@ pub fn Sidebar() -> impl IntoView {
|
||||
icon="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
|
||||
label="Tümü"
|
||||
count=Signal::derive(total_count)
|
||||
is_collapsed=is_collapsed.into()
|
||||
/>
|
||||
<SidebarItem
|
||||
active=Signal::derive(move || is_active(crate::store::FilterStatus::Downloading))
|
||||
on_click=move |_| set_filter(crate::store::FilterStatus::Downloading)
|
||||
icon="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"
|
||||
label="İndirilenler"
|
||||
count=Signal::derive(downloading_count)
|
||||
/>
|
||||
<SidebarItem
|
||||
active=Signal::derive(move || is_active(crate::store::FilterStatus::Seeding))
|
||||
on_click=move |_| set_filter(crate::store::FilterStatus::Seeding)
|
||||
icon="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5"
|
||||
label="Gönderilenler"
|
||||
count=Signal::derive(seeding_count)
|
||||
/>
|
||||
<SidebarItem
|
||||
active=Signal::derive(move || is_active(crate::store::FilterStatus::Completed))
|
||||
on_click=move |_| set_filter(crate::store::FilterStatus::Completed)
|
||||
icon="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
label="Tamamlananlar"
|
||||
count=Signal::derive(completed_count)
|
||||
/>
|
||||
<SidebarItem
|
||||
active=Signal::derive(move || is_active(crate::store::FilterStatus::Paused))
|
||||
on_click=move |_| set_filter(crate::store::FilterStatus::Paused)
|
||||
icon="M15.75 5.25v13.5m-7.5-13.5v13.5"
|
||||
label="Durdurulanlar"
|
||||
count=Signal::derive(paused_count)
|
||||
/>
|
||||
<SidebarItem
|
||||
active=Signal::derive(move || is_active(crate::store::FilterStatus::Inactive))
|
||||
on_click=move |_| set_filter(crate::store::FilterStatus::Inactive)
|
||||
icon="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"
|
||||
label="Pasif"
|
||||
count=Signal::derive(inactive_count)
|
||||
/>
|
||||
// ... (aynı mantık diğer itemler için de geçerli olacak)
|
||||
</SidenavMenu>
|
||||
</SidenavGroupContent>
|
||||
</SidenavGroup>
|
||||
</SidenavContent>
|
||||
|
||||
<SidenavFooter>
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
// Push Notification Toggle
|
||||
<div class="flex flex-col gap-4 p-2">
|
||||
// Push Toggle - Hide text when collapsed
|
||||
<div class="flex items-center justify-between px-2 py-1 bg-muted/20 rounded-md border border-border/50">
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<div class="flex flex-col gap-0.5" class:hidden=is_collapsed>
|
||||
<span class="text-[10px] font-bold uppercase tracking-wider text-foreground/70">"Bildirimler"</span>
|
||||
<span class="text-[9px] text-muted-foreground">"Web Push"</span>
|
||||
</div>
|
||||
<Switch
|
||||
checked=Signal::from(store.push_enabled)
|
||||
@@ -164,12 +134,14 @@ pub fn Sidebar() -> impl IntoView {
|
||||
<div class="h-8 w-8 rounded-full bg-primary text-primary-foreground flex items-center justify-center text-xs font-medium shrink-0 border border-primary-foreground/10">
|
||||
{first_letter}
|
||||
</div>
|
||||
<div class="flex-1 overflow-hidden">
|
||||
<div class="flex-1 overflow-hidden transition-all duration-300"
|
||||
class:opacity-0=is_collapsed
|
||||
class:w-0=is_collapsed>
|
||||
<div class="font-medium text-[11px] truncate text-foreground leading-tight">{username}</div>
|
||||
<div class="text-[9px] text-muted-foreground truncate opacity-70">"Yönetici"</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="flex items-center gap-1" class:hidden=is_collapsed>
|
||||
<ThemeToggle />
|
||||
|
||||
<Button
|
||||
|
||||
@@ -7,15 +7,15 @@ use crate::components::ui::button::{Button, ButtonVariant};
|
||||
use crate::components::ui::dialog::{
|
||||
Dialog, DialogTrigger, DialogContent, DialogBody, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose
|
||||
};
|
||||
use icons::Play;
|
||||
use icons::Plus;
|
||||
|
||||
#[component]
|
||||
pub fn AddTorrent() -> impl IntoView {
|
||||
view! {
|
||||
<Dialog>
|
||||
<DialogTrigger variant=ButtonVariant::Default class="gap-2">
|
||||
<Play class="size-4" />
|
||||
<span class="hidden sm:inline">"Add Torrent"</span>
|
||||
<DialogTrigger variant=ButtonVariant::Default class="gap-2 px-4">
|
||||
<Plus class="size-4" />
|
||||
<span>"Torrent Ekle"</span>
|
||||
</DialogTrigger>
|
||||
<DialogContent id="add-torrent-dialog">
|
||||
<AddTorrentDialogContent />
|
||||
@@ -48,7 +48,6 @@ pub fn AddTorrentDialogContent() -> impl IntoView {
|
||||
log::info!("Torrent added successfully");
|
||||
crate::store::toast_success("Torrent başarıyla eklendi");
|
||||
|
||||
// Programmatically close the dialog by triggering the close button
|
||||
if let Some(doc) = web_sys::window().and_then(|w| w.document()) {
|
||||
if let Some(el) = doc.get_element_by_id("add-torrent-dialog") {
|
||||
if let Some(close_btn) = el.query_selector("[data-dialog-close]").ok().flatten() {
|
||||
@@ -72,9 +71,9 @@ pub fn AddTorrentDialogContent() -> impl IntoView {
|
||||
view! {
|
||||
<DialogBody>
|
||||
<DialogHeader>
|
||||
<DialogTitle>"Add Torrent"</DialogTitle>
|
||||
<DialogTitle>"Torrent Ekle"</DialogTitle>
|
||||
<DialogDescription>
|
||||
"Enter a Magnet link or a .torrent file URL."
|
||||
"Magnet linki veya .torrent dosyası URL'si girin."
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -94,7 +93,7 @@ pub fn AddTorrentDialogContent() -> impl IntoView {
|
||||
|
||||
<DialogFooter class="pt-2">
|
||||
<DialogClose>
|
||||
"Cancel"
|
||||
"Vazgeç"
|
||||
</DialogClose>
|
||||
<Button
|
||||
attr:r#type="submit"
|
||||
@@ -103,10 +102,10 @@ pub fn AddTorrentDialogContent() -> impl IntoView {
|
||||
{move || if is_loading.0.get() {
|
||||
leptos::either::Either::Left(view! {
|
||||
<span class="animate-spin mr-2 h-4 w-4 border-2 border-current border-t-transparent rounded-full"></span>
|
||||
"Adding..."
|
||||
"Ekleniyor..."
|
||||
})
|
||||
} else {
|
||||
leptos::either::Either::Right(view! { "Add" })
|
||||
leptos::either::Either::Right(view! { "Ekle" })
|
||||
}}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
|
||||
@@ -1,57 +1,23 @@
|
||||
use leptos::prelude::*;
|
||||
use leptos_ui::{clx, variants, void};
|
||||
use leptos_ui::clx;
|
||||
use tw_merge::tw_merge;
|
||||
|
||||
mod components {
|
||||
use super::*;
|
||||
clx! {SidenavWrapper, div, "group/sidenav-wrapper has-data-[variant=Inset]:bg-sidenav flex h-full w-full"}
|
||||
clx! {SidenavInset, div, "bg-background relative flex w-full flex-1 flex-col data-[variant=Inset]:rounded-lg data-[variant=Inset]:border data-[variant=Inset]:border-sidenav-border data-[variant=Inset]:shadow-sm data-[variant=Inset]:m-2"}
|
||||
clx! {SidenavInner, div, "flex flex-col w-full h-full bg-sidenav data-[variant=Floating]:rounded-lg data-[variant=Floating]:border data-[variant=Floating]:border-sidenav-border data-[variant=Floating]:shadow-sm"}
|
||||
clx! {SidenavWrapper, div, "flex h-full w-full bg-background overflow-hidden"}
|
||||
clx! {SidenavInset, div, "bg-background relative flex w-full flex-1 flex-col min-w-0"}
|
||||
clx! {SidenavHeader, div, "flex flex-col gap-2 p-2"}
|
||||
clx! {SidenavMenu, ul, "flex flex-col gap-1 w-full min-w-0"}
|
||||
clx! {SidenavMenuSub, ul, "border-sidenav-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5 group-data-[collapsible=Icon]:hidden"}
|
||||
clx! {SidenavMenuItem, li, "relative group/menu-item"}
|
||||
clx! {SidenavContent, div, "scrollbar__on_hover", "flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=Icon]:overflow-hidden"}
|
||||
clx! {SidenavContent, div, "flex min-h-0 flex-1 flex-col gap-2 overflow-auto"}
|
||||
clx! {SidenavGroup, div, "flex relative flex-col p-2 w-full min-w-0"}
|
||||
clx! {SidenavGroupContent, div, "w-full text-sm"}
|
||||
clx! {SidenavGroupLabel, div, "text-sidenav-foreground/70 ring-sidenav-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0 group-data-[collapsible=Icon]:-mt-8 group-data-[collapsible=Icon]:opacity-0"}
|
||||
clx! {SidenavFooter, footer, "flex flex-col gap-2 p-2"}
|
||||
clx! {DropdownMenuTriggerEllipsis, button, "text-sidenav-foreground ring-sidenav-ring hover:bg-sidenav-accent hover:text-sidenav-accent-foreground peer-hover/menu-button:text-sidenav-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0 after:absolute after:-inset-2 md:after:hidden peer-data-[size=sm]/menu-button:top-1 peer-data-[size=default]/menu-button:top-1.5 peer-data-[size=lg]/menu-button:top-2.5 group-data-[collapsible=Icon]:hidden peer-data-[active=true]/menu-button:text-sidenav-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0"}
|
||||
|
||||
void! {SidenavInput, input,
|
||||
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"focus-visible:border-ring focus-visible:ring-ring/50",
|
||||
"focus-visible:ring-2",
|
||||
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
||||
"read-only:bg-muted",
|
||||
"w-full h-8 shadow-none bg-background"
|
||||
}
|
||||
clx! {SidenavGroupLabel, div, "text-muted-foreground/70 flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium uppercase tracking-wider"}
|
||||
clx! {SidenavMenu, ul, "flex flex-col gap-1 w-full min-w-0"}
|
||||
clx! {SidenavMenuItem, li, "relative"}
|
||||
clx! {SidenavFooter, footer, "flex flex-col gap-2 p-2 mt-auto"}
|
||||
}
|
||||
|
||||
pub use components::*;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display, strum::IntoStaticStr)]
|
||||
pub enum SidenavVariant {
|
||||
#[default]
|
||||
Sidenav,
|
||||
Floating,
|
||||
Inset,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display)]
|
||||
pub enum SidenavSide {
|
||||
#[default]
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy, PartialEq, Eq, strum::Display)]
|
||||
pub enum SidenavCollapsible {
|
||||
#[default]
|
||||
Offcanvas,
|
||||
None,
|
||||
Icon,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default, strum::Display)]
|
||||
pub enum SidenavState {
|
||||
#[default]
|
||||
@@ -61,92 +27,56 @@ pub enum SidenavState {
|
||||
|
||||
#[component]
|
||||
pub fn Sidenav(
|
||||
#[prop(into, optional)] class: String,
|
||||
#[prop(default = SidenavVariant::default())] variant: SidenavVariant,
|
||||
#[prop(optional, into)] class: String,
|
||||
#[prop(into)] data_state: Signal<SidenavState>,
|
||||
#[prop(default = SidenavSide::default())] data_side: SidenavSide,
|
||||
#[prop(default = SidenavCollapsible::default())] data_collapsible: SidenavCollapsible,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
let width_class = move || match data_state.get() {
|
||||
SidenavState::Expanded => "w-64",
|
||||
SidenavState::Collapsed => "w-16",
|
||||
};
|
||||
|
||||
view! {
|
||||
<aside
|
||||
data-name="Sidenav"
|
||||
data-state=move || data_state.get().to_string()
|
||||
data-side=data_side.to_string()
|
||||
data-collapsible=data_collapsible.to_string()
|
||||
class="hidden md:block group peer text-sidenav-foreground h-full"
|
||||
class=move || tw_merge!(
|
||||
"hidden md:flex flex-col border-r bg-card transition-all duration-300 ease-in-out h-full shrink-0 overflow-hidden",
|
||||
width_class(),
|
||||
class.clone()
|
||||
)
|
||||
>
|
||||
<div
|
||||
data-name="SidenavGap"
|
||||
class=tw_merge!(
|
||||
"relative w-(--sidenav-width) bg-transparent transition-[width] duration-200 ease-linear",
|
||||
"group-data-[collapsible=Offcanvas]:w-0",
|
||||
"group-data-[state=Collapsed]:w-(--sidenav-width-icon)",
|
||||
match variant {
|
||||
SidenavVariant::Sidenav => "group-data-[collapsible=Icon]:w-(--sidenav-width-icon)",
|
||||
SidenavVariant::Floating | SidenavVariant::Inset =>
|
||||
"group-data-[collapsible=Icon]:w-[calc(var(--sidenav-width-icon)+(--spacing(4)))]",
|
||||
}
|
||||
)
|
||||
/>
|
||||
<div
|
||||
data-name="SidenavContainer"
|
||||
class=tw_merge!(
|
||||
"fixed inset-y-0 z-10 hidden h-svh w-(--sidenav-width) transition-[left,right,width] duration-200 ease-linear md:flex",
|
||||
class,
|
||||
match data_side {
|
||||
SidenavSide::Left => "left-0 group-data-[collapsible=Offcanvas]:left-[calc(var(--sidenav-width)*-1)]",
|
||||
SidenavSide::Right => "right-0 group-data-[collapsible=Offcanvas]:right-[calc(var(--sidenav-width)*-1)]"
|
||||
},
|
||||
"group-data-[state=Collapsed]:w-(--sidenav-width-icon)",
|
||||
match variant {
|
||||
SidenavVariant::Sidenav => "group-data-[side=Left]:border-r group-data-[side=Right]:border-l",
|
||||
SidenavVariant::Floating | SidenavVariant::Inset => "p-2",
|
||||
},
|
||||
)
|
||||
>
|
||||
<SidenavInner attr:data-sidenav="Sidenav" attr:data-variant=variant.to_string()>
|
||||
{children()}
|
||||
</SidenavInner>
|
||||
</div>
|
||||
{children()}
|
||||
</aside>
|
||||
}
|
||||
}
|
||||
|
||||
variants! {
|
||||
SidenavMenuButton {
|
||||
base: "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidenav-ring transition-[width,height,padding] hover:bg-sidenav-accent hover:text-sidenav-accent-foreground focus-visible:ring-2 active:bg-sidenav-accent active:text-sidenav-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidenav=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-[current=page]:bg-sidenav-accent aria-[current=page]:font-medium aria-[current=page]:text-sidenav-accent-foreground data-[state=open]:hover:bg-sidenav-accent data-[state=open]:hover:text-sidenav-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 group-data-[state=Collapsed]:size-8! group-data-[state=Collapsed]:p-0! [&>svg]:stroke-2 aria-[current=page]:[&>svg]:stroke-[2.7]",
|
||||
variants: {
|
||||
variant: {
|
||||
Default: "hover:bg-sidenav-accent hover:text-sidenav-accent-foreground",
|
||||
Outline: "bg-background shadow-[0_0_0_1px_hsl(var(--sidenav-border))] hover:bg-sidenav-accent hover:text-sidenav-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidenav-accent))]",
|
||||
},
|
||||
size: {
|
||||
Default: "h-8 text-sm",
|
||||
Sm: "h-7 text-xs",
|
||||
Lg: "h-12",
|
||||
}
|
||||
},
|
||||
component: {
|
||||
element: button,
|
||||
support_href: true,
|
||||
support_aria_current: true
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default)]
|
||||
pub enum SidenavMenuButtonVariant { #[default] Default, Outline }
|
||||
|
||||
#[component]
|
||||
pub fn SidenavMenuButton(
|
||||
children: Children,
|
||||
#[prop(into, optional)] variant: Signal<SidenavMenuButtonVariant>,
|
||||
#[prop(into, optional)] class: Signal<String>,
|
||||
) -> impl IntoView {
|
||||
let class_signal = move || tw_merge!(
|
||||
"flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground whitespace-nowrap overflow-hidden",
|
||||
if variant.get() == SidenavMenuButtonVariant::Outline { "border border-input bg-background shadow-sm" } else { "" },
|
||||
class.get()
|
||||
);
|
||||
view! { <button class=class_signal>{children()}</button> }
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn SidenavTrigger(
|
||||
#[prop(into)] data_state: RwSignal<SidenavState>,
|
||||
#[prop(optional, into)] class: String,
|
||||
) -> impl IntoView {
|
||||
view! {
|
||||
<button
|
||||
on:click=move |_| data_state.update(|s| *s = match s { SidenavState::Expanded => SidenavState::Collapsed, SidenavState::Collapsed => SidenavState::Expanded })
|
||||
data-name="SidenavTrigger"
|
||||
class=tw_merge!("inline-flex gap-2 justify-center items-center text-sm font-medium whitespace-nowrap rounded-md transition-all outline-none size-7 hover:bg-accent hover:text-accent-foreground focus-visible:ring-2", class)
|
||||
class="p-2 rounded-md hover:bg-accent text-muted-foreground transition-colors"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-panel-left"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user