updated README

This commit is contained in:
anthdm 2024-06-09 11:16:23 +02:00
parent f09320161b
commit 1692d4eb83
6 changed files with 137 additions and 58 deletions

View file

@ -1,6 +1,21 @@
# GOTHKIT # GOTHKIT
Create interactive applications with Golang, HTMX, and Templ
> NOT READY (YET)
## Table of content
- [GOTHKIT](#gothkit)
- [Table of content](#table-of-content)
- [Installation](#installation)
- [Getting started](#getting-started)
- [Development server](#development-server)
- [Hot reloading the browser](#hot-reloading-the-browser)
- [Migrations](#migrations)
- [Create a new migration](#create-a-new-migration)
- [Migrate the database](#migrate-the-database)
- [Reset the database](#reset-the-database)
- [Seeds](#seeds)
- [Testing](#testing)
- [Testing handlers](#testing-handlers)
# Installation # Installation
``` ```
@ -12,42 +27,49 @@ After installation you can create a new project by running:
gothkit [myprojectname] gothkit [myprojectname]
``` ```
Navigate to your project and start the development server: You can now navigate to your project:
``` ```
cd [myprojectname] cd [myprojectname]
make dev
``` ```
# Getting started # Getting started
## Hot reloading the browser ## Development server
Hot reloading is configured by default, the only thing left to do is watching for changes to your assets by running the following command: Run the development server with the following command:
``` ```
make assets make dev
``` ```
## Migrations ## Hot reloading the browser
### Create a new migration Hot reloading is configured by default when running your application in development.
> NOTE: on windows you might need to run `make assets` in another terminal for god knows why.
# Migrations
## Create a new migration
``` ```
make db-mig add_user_table make db-mig add_user_table
``` ```
### Migrate the database Will create a new migration SQL file inside `app/db/migrations`
## Migrate the database
``` ```
make db-up make db-up
``` ```
### Reset the database ## Reset the database
``` ```
make db-reset make db-reset
``` ```
### Seed the database ## Seeds
``` ```
make db-seed make db-seed
``` ```
This command will run the seeds file located at `cmd/scripts/seed/main.go`
# Testing
## Testing handlers

View file

@ -3,7 +3,7 @@ package components
templ Navigation() { templ Navigation() {
<nav class="border-b py-3"> <nav class="border-b py-3">
<div class="container mx-auto flex justify-between"> <div class="container mx-auto flex justify-between">
<div class="text-lg text-red-500"> <div class="text-lg text-foreground">
<a href="/" class="font-semibold uppercase">Gothkit <span class="text-sm">v0.1</span></a> <a href="/" class="font-semibold uppercase">Gothkit <span class="text-sm">v0.1</span></a>
</div> </div>
<div class="flex gap-4 items-center"> <div class="flex gap-4 items-center">

View file

@ -7,8 +7,10 @@ import (
templ Index() { templ Index() {
@layouts.App() { @layouts.App() {
<div class="mt-20 text-center flex flex-col gap-10"> <div class="mt-20 text-center flex flex-col gap-10">
<h1 class="max-w-xl mx-auto tracking-wider text-3xl lg:text-6xl font-bold">A single binary to change the world</h1> <h1 class="max-w-xl mx-auto text-3xl lg:text-6xl font-bold">A single binary to change the world</h1>
<a class="text-xl underline text-blue-500" target="_blank" href="https://github.com/anthdm/gothkit">Get started by reading the documentation</a> <div class="flex justify-center">
<a href="https://github.com/anthdm/gothkit" target="_blank" class="bg-primary w-fit rounded-md px-4 py-2 text-primary-foreground">Getting started</a>
</div>
</div> </div>
} }
} }

View file

@ -46,7 +46,7 @@ html,
-o-tab-size: 4; -o-tab-size: 4;
tab-size: 4; tab-size: 4;
/* 3 */ /* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
/* 4 */ /* 4 */
font-feature-settings: normal; font-feature-settings: normal;
/* 5 */ /* 5 */
@ -628,6 +628,10 @@ body {
display: flex; display: flex;
} }
.grid {
display: grid;
}
.h-screen { .h-screen {
height: 100vh; height: 100vh;
} }
@ -636,6 +640,11 @@ body {
width: 100%; width: 100%;
} }
.w-fit {
width: -moz-fit-content;
width: fit-content;
}
.max-w-7xl { .max-w-7xl {
max-width: 80rem; max-width: 80rem;
} }
@ -644,10 +653,18 @@ body {
max-width: 36rem; max-width: 36rem;
} }
.max-w-5xl {
max-width: 64rem;
}
.cursor-pointer { .cursor-pointer {
cursor: pointer; cursor: pointer;
} }
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.flex-col { .flex-col {
flex-direction: column; flex-direction: column;
} }
@ -672,12 +689,12 @@ body {
gap: 1rem; gap: 1rem;
} }
.gap-8 { .rounded-md {
gap: 2rem; border-radius: calc(var(--radius) - 2px);
} }
.rounded-full { .rounded-sm {
border-radius: 9999px; border-radius: calc(var(--radius) - 4px);
} }
.border { .border {
@ -688,17 +705,13 @@ body {
border-bottom-width: 1px; border-bottom-width: 1px;
} }
.border-black { .bg-primary {
--tw-border-opacity: 1; --tw-bg-opacity: 1;
border-color: rgb(0 0 0 / var(--tw-border-opacity)); background-color: hsl(var(--primary) / var(--tw-bg-opacity));
} }
.p-1 { .p-2 {
padding: 0.25rem; padding: 0.5rem;
}
.p-1\.5 {
padding: 0.375rem;
} }
.py-3 { .py-3 {
@ -706,6 +719,31 @@ body {
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
} }
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.px-3 {
padding-left: 0.75rem;
padding-right: 0.75rem;
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.text-center { .text-center {
text-align: center; text-align: center;
} }
@ -747,12 +785,12 @@ body {
font-weight: 600; font-weight: 600;
} }
.uppercase { .font-black {
text-transform: uppercase; font-weight: 900;
} }
.tracking-wide { .uppercase {
letter-spacing: 0.025em; text-transform: uppercase;
} }
.tracking-wider { .tracking-wider {
@ -774,6 +812,26 @@ body {
color: rgb(239 68 68 / var(--tw-text-opacity)); color: rgb(239 68 68 / var(--tw-text-opacity));
} }
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-foreground {
--tw-text-opacity: 1;
color: hsl(var(--foreground) / var(--tw-text-opacity));
}
.text-primary {
--tw-text-opacity: 1;
color: hsl(var(--primary) / var(--tw-text-opacity));
}
.text-primary-foreground {
--tw-text-opacity: 1;
color: hsl(var(--primary-foreground) / var(--tw-text-opacity));
}
.underline { .underline {
text-decoration-line: underline; text-decoration-line: underline;
} }
@ -784,10 +842,3 @@ body {
line-height: 1; line-height: 1;
} }
} }
@media (prefers-color-scheme: dark) {
.dark\:border-white {
--tw-border-opacity: 1;
border-color: rgb(255 255 255 / var(--tw-border-opacity));
}
}

View file

@ -72,19 +72,14 @@ var ContainsUpper = RuleSet{
}, },
} }
var ContainsNumeric = RuleSet{ var ContainsDigit = RuleSet{
Name: "containsNumeric", Name: "containsDigit",
ValidateFunc: func(rule RuleSet) bool { ValidateFunc: func(rule RuleSet) bool {
str, ok := rule.FieldValue.(string) str, ok := rule.FieldValue.(string)
if !ok { if !ok {
return false return false
} }
for _, ch := range str { return hasDigit(str)
if isSpecial(ch) {
return true
}
}
return false
}, },
MessageFunc: func(set RuleSet) string { MessageFunc: func(set RuleSet) string {
return "must contain at least 1 numeric character" return "must contain at least 1 numeric character"
@ -98,12 +93,7 @@ var ContainsSpecial = RuleSet{
if !ok { if !ok {
return false return false
} }
for _, ch := range str { return hasSpecialChar(str)
if isSpecial(ch) {
return true
}
}
return false
}, },
MessageFunc: func(set RuleSet) string { MessageFunc: func(set RuleSet) string {
return "must contain at least 1 special character" return "must contain at least 1 special character"
@ -297,6 +287,20 @@ func Min(n int) RuleSet {
} }
} }
func isSpecial(ch rune) bool { func hasDigit(s string) bool {
return true for _, char := range s {
if unicode.IsDigit(char) {
return true
}
}
return false
}
func hasSpecialChar(s string) bool {
for _, char := range s {
if !unicode.IsLetter(char) && !unicode.IsDigit(char) {
return true
}
}
return false
} }

View file

@ -19,7 +19,7 @@ var testSchema = Schema{
"password": Rules( "password": Rules(
ContainsSpecial, ContainsSpecial,
ContainsUpper, ContainsUpper,
ContainsNumeric, ContainsDigit,
Min(7), Min(7),
Max(50), Max(50),
), ),