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
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
```
@ -12,42 +27,49 @@ After installation you can create a new project by running:
gothkit [myprojectname]
```
Navigate to your project and start the development server:
You can now navigate to your project:
```
cd [myprojectname]
make dev
```
# Getting started
## Hot reloading the browser
Hot reloading is configured by default, the only thing left to do is watching for changes to your assets by running the following command:
## Development server
Run the development server with the following command:
```
make assets
make dev
```
## Migrations
### Create a new migration
## Hot reloading the browser
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
```
### Migrate the database
Will create a new migration SQL file inside `app/db/migrations`
## Migrate the database
```
make db-up
```
### Reset the database
## Reset the database
```
make db-reset
```
### Seed the database
## Seeds
```
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() {
<nav class="border-b py-3">
<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>
</div>
<div class="flex gap-4 items-center">

View file

@ -7,8 +7,10 @@ import (
templ Index() {
@layouts.App() {
<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>
<a class="text-xl underline text-blue-500" target="_blank" href="https://github.com/anthdm/gothkit">Get started by reading the documentation</a>
<h1 class="max-w-xl mx-auto text-3xl lg:text-6xl font-bold">A single binary to change the world</h1>
<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>
}
}

View file

@ -46,7 +46,7 @@ html,
-o-tab-size: 4;
tab-size: 4;
/* 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 */
font-feature-settings: normal;
/* 5 */
@ -628,6 +628,10 @@ body {
display: flex;
}
.grid {
display: grid;
}
.h-screen {
height: 100vh;
}
@ -636,6 +640,11 @@ body {
width: 100%;
}
.w-fit {
width: -moz-fit-content;
width: fit-content;
}
.max-w-7xl {
max-width: 80rem;
}
@ -644,10 +653,18 @@ body {
max-width: 36rem;
}
.max-w-5xl {
max-width: 64rem;
}
.cursor-pointer {
cursor: pointer;
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.flex-col {
flex-direction: column;
}
@ -672,12 +689,12 @@ body {
gap: 1rem;
}
.gap-8 {
gap: 2rem;
.rounded-md {
border-radius: calc(var(--radius) - 2px);
}
.rounded-full {
border-radius: 9999px;
.rounded-sm {
border-radius: calc(var(--radius) - 4px);
}
.border {
@ -688,17 +705,13 @@ body {
border-bottom-width: 1px;
}
.border-black {
--tw-border-opacity: 1;
border-color: rgb(0 0 0 / var(--tw-border-opacity));
.bg-primary {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary) / var(--tw-bg-opacity));
}
.p-1 {
padding: 0.25rem;
}
.p-1\.5 {
padding: 0.375rem;
.p-2 {
padding: 0.5rem;
}
.py-3 {
@ -706,6 +719,31 @@ body {
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-align: center;
}
@ -747,12 +785,12 @@ body {
font-weight: 600;
}
.uppercase {
text-transform: uppercase;
.font-black {
font-weight: 900;
}
.tracking-wide {
letter-spacing: 0.025em;
.uppercase {
text-transform: uppercase;
}
.tracking-wider {
@ -774,6 +812,26 @@ body {
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 {
text-decoration-line: underline;
}
@ -784,10 +842,3 @@ body {
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{
Name: "containsNumeric",
var ContainsDigit = RuleSet{
Name: "containsDigit",
ValidateFunc: func(rule RuleSet) bool {
str, ok := rule.FieldValue.(string)
if !ok {
return false
}
for _, ch := range str {
if isSpecial(ch) {
return true
}
}
return false
return hasDigit(str)
},
MessageFunc: func(set RuleSet) string {
return "must contain at least 1 numeric character"
@ -98,12 +93,7 @@ var ContainsSpecial = RuleSet{
if !ok {
return false
}
for _, ch := range str {
if isSpecial(ch) {
return true
}
}
return false
return hasSpecialChar(str)
},
MessageFunc: func(set RuleSet) string {
return "must contain at least 1 special character"
@ -297,6 +287,20 @@ func Min(n int) RuleSet {
}
}
func isSpecial(ch rune) bool {
return true
func hasDigit(s string) bool {
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(
ContainsSpecial,
ContainsUpper,
ContainsNumeric,
ContainsDigit,
Min(7),
Max(50),
),