Files
sonr/pkg/webapp/components/ui/layout.templ
T

181 lines
6.5 KiB
Templ
Raw Normal View History

package ui
2024-10-07 20:14:46 -04:00
// Variant is a component that has attributes
2024-10-07 20:14:46 -04:00
type Variant interface {
Attributes() templ.Attributes
}
// ╭───────────────────────────────────────────────────────────╮
// │ General Layout Components │
// ╰───────────────────────────────────────────────────────────╯
2024-10-07 20:14:46 -04:00
// Columns is a component that renders a flex container with a gap of 3 and a max width of 100%
2024-10-07 20:14:46 -04:00
templ Columns() {
<div class="flex flex-col h-full w-full gap-3 md:gap-6 md:flex-row">
{ children... }
</div>
}
// Layout is a component that renders the general layout of the application
2024-09-29 14:40:36 -04:00
templ Layout(title string, remote bool) {
<!DOCTYPE html>
<html lang="en">
<head>
@Styles()
@Htmx()
@Alpine()
@WebAwesome()
2024-09-29 14:40:36 -04:00
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{ title }</title>
<!-- Sets the status bar style to transparent -->
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
2024-10-01 19:36:15 -04:00
<link rel="icon" type="image/png" href="https://cdn.sonr.id/favicon.png"/>
2024-09-29 14:40:36 -04:00
</head>
<body class="flex items-center justify-center h-full bg-neutral-50 lg:p-24 md:16 p-4">
@Toaster() {
<main class="flex-row items-center justify-center mx-auto w-fit max-w-screen-sm gap-y-3">
{ children... }
</main>
}
2024-09-29 14:40:36 -04:00
</body>
</html>
}
// LayoutNoBody is a component that renders the general layout of the application without the body tag
2024-09-29 14:40:36 -04:00
templ LayoutNoBody(title string, remote bool) {
<!DOCTYPE html>
<html lang="en">
<head>
@Styles()
@Htmx()
@Alpine()
@WebAwesome()
2024-09-29 14:40:36 -04:00
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{ title }</title>
2024-10-01 19:36:15 -04:00
<link rel="icon" type="image/png" href="https://cdn.sonr.id/favicon.png"/>
2024-09-29 14:40:36 -04:00
<!-- Sets the status bar style to transparent -->
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
</head>
<main class="grow">
2024-09-29 21:42:46 -04:00
<body class="font-inter antialiased bg-white text-zinc-900 tracking-tight">
@Toaster() {
<div class="flex flex-col min-h-screen overflow-hidden supports-[overflow:clip]:overflow-clip">
{ children... }
</div>
}
2024-09-29 21:42:46 -04:00
</body>
2024-09-29 14:40:36 -04:00
</main>
</html>
}
2024-10-07 10:39:50 -04:00
// OpenModal is a component that renders a modal with a title and description
2024-10-07 13:59:29 -04:00
templ OpenModal(title, description string) {
2024-10-07 10:39:50 -04:00
<div
x-data="{ modalOpen: true }"
@keydown.escape="modalOpen=false"
:class="{ 'z-40': modalOpen }"
class="relative w-auto h-auto"
>
<template x-teleport="body">
<div x-show="modalOpen" class="fixed top-0 left-0 z-[99] flex items-center justify-center w-screen h-screen" x-cloak>
<div
x-show="modalOpen"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-300"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
@click="modalOpen=false"
2024-10-07 13:59:29 -04:00
class="absolute inset-0 w-full h-full bg-zinc-900 bg-opacity-90 backdrop-blur-sm"
2024-10-07 10:39:50 -04:00
></div>
<div
x-show="modalOpen"
x-trap.inert.noscroll="modalOpen"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
class="relative w-full py-6 bg-white shadow-md px-7 bg-opacity-90 drop-shadow-md backdrop-blur-sm sm:max-w-lg sm:rounded-lg"
>
<div class="flex items-center justify-between pb-3">
<h3 class="text-lg font-semibold">{ title }</h3>
<button @click="modalOpen=false" class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-zinc-600 rounded-full hover:text-zinc-800 hover:bg-zinc-50">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
</div>
<div class="relative w-auto pb-8">
<p>{ description }</p>
</div>
{ children... }
</div>
</div>
</template>
</div>
}
templ FullScreenModal() {
<div
x-data="{ fullscreenModal: true }"
x-init="
$watch('fullscreenModal', function(value){
if(value === true){
document.body.classList.add('overflow-hidden');
}else{
document.body.classList.remove('overflow-hidden');
}
})
"
@keydown.escape="fullscreenModal=false"
>
<template x-teleport="body">
<div
x-show="fullscreenModal"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="flex fixed inset-0 z-[99] w-screen h-screen bg-white"
>
<button @click="fullscreenModal=false" class="absolute top-0 right-0 z-30 flex items-center justify-center px-3 py-3 mt-5 mr-5 space-x-1 text-xs font-medium uppercase rounded-full text-zinc-500 hover:bg-zinc-200">
<svg class="w-8 h-8" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"></path></svg>
</button>
<div class="relative flex flex-wrap items-center w-full h-full px-8">
{ children... }
</div>
</div>
</template>
</div>
}
// Rows is a component that renders a flex container with a gap of 2 and a max width of 100%
templ Rows() {
<div class="flex flex-row w-full gap-2 md:gap-4">
{ children... }
</div>
}
// Spacer is a component that renders a <br/> tag
templ Spacer() {
<br/>
}
templ Separator(text string) {
<div class="relative py-6">
<div class="absolute inset-0 flex items-center"><span class="w-full border-t"></span></div>
<div class="relative flex justify-center text-xs uppercase">
<span class="px-2 bg-white text-neutral-500">{ text }</span>
</div>
</div>
}