Add tags
This commit is contained in:
parent
dabcd7b75a
commit
4c02dbb1d4
7 changed files with 221 additions and 64 deletions
|
@ -7,4 +7,4 @@ indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
[*.{yaml,yml}]
|
[*.{yaml,yml}]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
let count: number = 0
|
|
||||||
const increment = () => {
|
|
||||||
count += 1
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<button on:click={increment}>
|
|
||||||
count is {count}
|
|
||||||
</button>
|
|
|
@ -20,13 +20,20 @@
|
||||||
let newItemName = "";
|
let newItemName = "";
|
||||||
let newItemDate = (new Date()).toISOString().split("T")[0];
|
let newItemDate = (new Date()).toISOString().split("T")[0];
|
||||||
let newItemDuration = "1h";
|
let newItemDuration = "1h";
|
||||||
|
let newItemRawTags = "";
|
||||||
|
$: newItemTags = newItemRawTags.split(";").filter(x => x);
|
||||||
|
|
||||||
function createItem() {
|
function createItem() {
|
||||||
$createMutation.mutate({
|
$createMutation.mutate({
|
||||||
name: newItemName,
|
name: newItemName,
|
||||||
date: newItemDate,
|
date: newItemDate,
|
||||||
duration: newItemDuration
|
duration: newItemDuration,
|
||||||
|
tags: newItemTags
|
||||||
});
|
});
|
||||||
|
|
||||||
|
newItemName = "";
|
||||||
|
newItemDuration = "1h";
|
||||||
|
document.getElementById("name-input").focus();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -62,7 +69,12 @@
|
||||||
<div class="vstack gap-3 justify-content-center h-100">
|
<div class="vstack gap-3 justify-content-center h-100">
|
||||||
{#each items as item}
|
{#each items as item}
|
||||||
<div class="hstack gap-3">
|
<div class="hstack gap-3">
|
||||||
<span class="me-auto">{item.name}</span>
|
<span class="me-auto">
|
||||||
|
{item.name}
|
||||||
|
{#each item.tags as tag}
|
||||||
|
<span class="badge bg-info me-1">{tag.name}</span>
|
||||||
|
{/each}
|
||||||
|
</span>
|
||||||
<button type="button" class="btn btn-danger btn-sm" on:click={() => {
|
<button type="button" class="btn btn-danger btn-sm" on:click={() => {
|
||||||
if (!confirm(`Are you sure you want to delete "${item.name}"?`)) return;
|
if (!confirm(`Are you sure you want to delete "${item.name}"?`)) return;
|
||||||
$deleteMutation.mutate(item.id)
|
$deleteMutation.mutate(item.id)
|
||||||
|
@ -79,7 +91,7 @@
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<h2>New</h2>
|
<h2>New</h2>
|
||||||
<form on:submit|preventDefault={createItem}>
|
<form on:submit|preventDefault={createItem}>
|
||||||
|
@ -95,15 +107,24 @@
|
||||||
<label for="duration-input" class="form-label">Duration</label>
|
<label for="duration-input" class="form-label">Duration</label>
|
||||||
<input type="text" class="form-control" id="duration-input" bind:value={newItemDuration} required />
|
<input type="text" class="form-control" id="duration-input" bind:value={newItemDuration} required />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="tags-input" class="form-label">Tags</label>
|
||||||
|
<input type="text" class="form-control" id="tags-input" bind:value={newItemRawTags} />
|
||||||
|
<div class="form-text">
|
||||||
|
{#each newItemTags as tag}
|
||||||
|
<span class="badge bg-info me-1">{tag}</span>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Raw Data</h2>
|
<h2>Raw Data</h2>
|
||||||
{#if $queryResult.data}
|
{#if $queryResult.data}
|
||||||
<div class="small mt-2">
|
<div class="small mt-2">
|
||||||
<pre><code>{JSON.stringify($queryResult.data, null, 2)}</code></pre>
|
<pre><code>{JSON.stringify($queryResult.data, null, 2)}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
const SCHEDULE_DAYS = 14;
|
const SCHEDULE_DAYS = 14;
|
||||||
const API_URL = import.meta.env.PROD ? "/api" : import.meta.env.VITE_API_URL;
|
const API_URL = import.meta.env.PROD ? "/api" : import.meta.env.VITE_API_URL;
|
||||||
|
|
||||||
|
type ScheduleTag = {
|
||||||
|
id: number,
|
||||||
|
createdAt: string,
|
||||||
|
updatedAt: string,
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
type ScheduleItem = {
|
type ScheduleItem = {
|
||||||
id: number,
|
id: number,
|
||||||
createdAt: string,
|
createdAt: string,
|
||||||
|
@ -9,12 +16,14 @@ type ScheduleItem = {
|
||||||
description: string | null,
|
description: string | null,
|
||||||
duration: string,
|
duration: string,
|
||||||
date: string
|
date: string
|
||||||
|
tags: ScheduleTag[]
|
||||||
};
|
};
|
||||||
|
|
||||||
type Schedule = { [date: string]: ScheduleItem[] };
|
type Schedule = { [date: string]: ScheduleItem[] };
|
||||||
|
|
||||||
export async function getSchedule(): Promise<Schedule> {
|
export async function getSchedule(): Promise<Schedule> {
|
||||||
const res = await fetch(`${API_URL}/schedule?days=${SCHEDULE_DAYS}`);
|
const res = await fetch(`${API_URL}/schedule?days=${SCHEDULE_DAYS}`);
|
||||||
|
|
||||||
if (res?.ok) {
|
if (res?.ok) {
|
||||||
return await res.json();
|
return await res.json();
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,7 +31,7 @@ export async function getSchedule(): Promise<Schedule> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createScheduleItem(data: { name: string, duration: string, date: string }) {
|
export async function createScheduleItem(data: { name: string, duration: string, date: string, tags: string[] }) {
|
||||||
const res = await fetch(`${API_URL}/items`, {
|
const res = await fetch(`${API_URL}/items`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -33,7 +42,7 @@ export async function createScheduleItem(data: { name: string, duration: string,
|
||||||
date: new Date(data.date).toISOString()
|
date: new Date(data.date).toISOString()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res?.ok) {
|
if (res?.ok) {
|
||||||
return await res.json();
|
return await res.json();
|
||||||
} else {
|
} else {
|
||||||
|
@ -45,10 +54,10 @@ export async function deleteScheduleItem(id: number) {
|
||||||
const res = await fetch(`${API_URL}/items/${id}`, {
|
const res = await fetch(`${API_URL}/items/${id}`, {
|
||||||
method: "DELETE"
|
method: "DELETE"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res?.ok) {
|
if (res?.ok) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Invalid response code ${res?.status}`);
|
throw new Error(`Invalid response code ${res?.status}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,18 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetScheduleItems(db *gorm.DB, fromDate time.Time, toDate time.Time) ([]ScheduleItem, error) {
|
func GetScheduleItems(db *gorm.DB, fromDate time.Time, toDate time.Time) ([]ScheduleItem, error) {
|
||||||
var items []ScheduleItem
|
var items []ScheduleItem
|
||||||
res := db.Where("date BETWEEN ? AND ?", fromDate.Format(time.DateOnly), toDate.Format(time.DateOnly)).Find(&items)
|
res := db.Preload("Tags").Where("date BETWEEN ? AND ?", fromDate.Format(time.DateOnly), toDate.Format(time.DateOnly)).Find(&items)
|
||||||
return items, res.Error
|
return items, res.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetScheduleItem(db *gorm.DB, id int) (*ScheduleItem, error) {
|
func GetScheduleItem(db *gorm.DB, id int) (*ScheduleItem, error) {
|
||||||
var item ScheduleItem
|
var item ScheduleItem
|
||||||
res := db.First(&item, id)
|
res := db.Preload("Tags").First(&item, id)
|
||||||
|
|
||||||
if res.RowsAffected < 1 {
|
if res.RowsAffected < 1 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -37,15 +38,83 @@ func DeleteScheduleItem(db *gorm.DB, id int) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateScheduleItem(db *gorm.DB, name string, description *string, duration Duration, date time.Time) (ScheduleItem, error) {
|
func CreateScheduleItem(db *gorm.DB, name string, description *string, duration Duration, date time.Time, tagNames []string) (ScheduleItem, error) {
|
||||||
|
var tags = []ScheduleTag{}
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(tagNames) > 0 {
|
||||||
|
tags, err = UpsertScheduleTags(db, tagNames)
|
||||||
|
if err != nil {
|
||||||
|
return ScheduleItem{}, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item := ScheduleItem{
|
item := ScheduleItem{
|
||||||
Name: name,
|
Name: name,
|
||||||
Description: description,
|
Description: description,
|
||||||
Duration: duration,
|
Duration: duration,
|
||||||
Date: date,
|
Date: date,
|
||||||
|
Tags: tags,
|
||||||
}
|
}
|
||||||
|
|
||||||
res := db.Create(&item)
|
res := db.Create(&item)
|
||||||
|
|
||||||
return item, res.Error
|
return item, res.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetScheduleTags(db *gorm.DB) ([]ScheduleTag, error) {
|
||||||
|
var tags []ScheduleTag
|
||||||
|
res := db.Find(&tags)
|
||||||
|
return tags, res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetScheduleTag(db *gorm.DB, id int) (*ScheduleTag, error) {
|
||||||
|
var tag ScheduleTag
|
||||||
|
res := db.First(&tag, id)
|
||||||
|
|
||||||
|
if res.RowsAffected < 1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tag, res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteScheduleTag(db *gorm.DB, id int) (bool, error) {
|
||||||
|
res := db.Delete(&ScheduleTag{}, id)
|
||||||
|
|
||||||
|
if res.Error != nil {
|
||||||
|
return false, res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.RowsAffected < 1 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateScheduleTag(db *gorm.DB, name string) (ScheduleTag, error) {
|
||||||
|
tag := ScheduleTag{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
res := db.Create(&tag)
|
||||||
|
|
||||||
|
return tag, res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpsertScheduleTags(db *gorm.DB, names []string) ([]ScheduleTag, error) {
|
||||||
|
var tags = []ScheduleTag{}
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
tags = append(tags, ScheduleTag{Name: name})
|
||||||
|
}
|
||||||
|
|
||||||
|
res := db.Clauses(clause.OnConflict{DoNothing: true}).Create(&tags)
|
||||||
|
return tags, res.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func Cleanup(db *gorm.DB) error {
|
||||||
|
res := db.Exec("select * from schedule_tags where id not in (select schedule_tag_id from schedule_item_tags);")
|
||||||
|
return res.Error
|
||||||
|
}
|
||||||
|
|
130
main.go
130
main.go
|
@ -1,15 +1,16 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
"log"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/filesystem"
|
||||||
|
|
||||||
|
"github.com/glebarez/sqlite"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
"github.com/glebarez/sqlite"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -17,18 +18,24 @@ import (
|
||||||
var f embed.FS
|
var f embed.FS
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
ID uint `gorm:"primaryKey;not null" json:"id"`
|
ID uint `gorm:"primaryKey;not null" json:"id"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScheduleItem struct {
|
type ScheduleItem struct {
|
||||||
Model
|
Model
|
||||||
Name string `gorm:"not null" json:"name"`
|
Name string `gorm:"not null" json:"name"`
|
||||||
Description *string `json:"description"`
|
Description *string `json:"description"`
|
||||||
Duration Duration `gorm:"not null;default:\"1h\"" json:"duration"`
|
Duration Duration `gorm:"not null;default:\"1h\"" json:"duration"`
|
||||||
Date time.Time `gorm:"not null" json:"date"`
|
Date time.Time `gorm:"not null" json:"date"`
|
||||||
|
Tags []ScheduleTag `gorm:"many2many:schedule_item_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScheduleTag struct {
|
||||||
|
Model
|
||||||
|
Name string `gorm:"not null;unique;index" json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewScheduleItem struct {
|
type NewScheduleItem struct {
|
||||||
|
@ -36,6 +43,11 @@ type NewScheduleItem struct {
|
||||||
Description *string `json:"description" form:"description"`
|
Description *string `json:"description" form:"description"`
|
||||||
Duration *Duration `json:"duration" form:"duration"`
|
Duration *Duration `json:"duration" form:"duration"`
|
||||||
Date *time.Time `json:"date" form:"date"`
|
Date *time.Time `json:"date" form:"date"`
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NewScheduleTag struct {
|
||||||
|
Name *string `json:"name" form:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDateValues(c *fiber.Ctx) (time.Time, time.Time, error) {
|
func getDateValues(c *fiber.Ctx) (time.Time, time.Time, error) {
|
||||||
|
@ -63,7 +75,7 @@ func getDateValues(c *fiber.Ctx) (time.Time, time.Time, error) {
|
||||||
func dateRange(from time.Time, to time.Time) []time.Time {
|
func dateRange(from time.Time, to time.Time) []time.Time {
|
||||||
var dates []time.Time
|
var dates []time.Time
|
||||||
|
|
||||||
for d := from; d.After(to) == false; d = d.AddDate(0, 0, 1) {
|
for d := from; !d.After(to); d = d.AddDate(0, 0, 1) {
|
||||||
dates = append(dates, d)
|
dates = append(dates, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,13 +88,13 @@ func main() {
|
||||||
log.Fatalf("failed to open database: %v", err)
|
log.Fatalf("failed to open database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.AutoMigrate(&ScheduleItem{})
|
err = db.AutoMigrate(&ScheduleItem{}, &ScheduleTag{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to migrate database: %v", err)
|
log.Fatalf("failed to migrate database: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
|
|
||||||
app.Use(cors.New())
|
app.Use(cors.New())
|
||||||
|
|
||||||
app.Get("/api/items", func(c *fiber.Ctx) error {
|
app.Get("/api/items", func(c *fiber.Ctx) error {
|
||||||
|
@ -109,7 +121,7 @@ func main() {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.Name == nil || len(*input.Name) < 0 {
|
if input.Name == nil || len(*input.Name) == 0 {
|
||||||
return c.Status(fiber.StatusBadRequest).SendString("Name is required")
|
return c.Status(fiber.StatusBadRequest).SendString("Name is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +133,7 @@ func main() {
|
||||||
return c.Status(fiber.StatusBadRequest).SendString("Date is required")
|
return c.Status(fiber.StatusBadRequest).SendString("Date is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := CreateScheduleItem(db, *input.Name, input.Description, *input.Duration, *input.Date)
|
item, err := CreateScheduleItem(db, *input.Name, input.Description, *input.Duration, *input.Date, input.Tags)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("failed to create schedule item: %v", err)
|
log.Printf("failed to create schedule item: %v", err)
|
||||||
|
@ -144,7 +156,7 @@ func main() {
|
||||||
log.Printf("failed to find schedule items: %v", err)
|
log.Printf("failed to find schedule items: %v", err)
|
||||||
return c.SendStatus(fiber.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule := map[string][]ScheduleItem{}
|
schedule := map[string][]ScheduleItem{}
|
||||||
|
|
||||||
for _, date := range dateRange(fromDate, toDate) {
|
for _, date := range dateRange(fromDate, toDate) {
|
||||||
|
@ -197,11 +209,83 @@ func main() {
|
||||||
|
|
||||||
return c.SendStatus(http.StatusOK)
|
return c.SendStatus(http.StatusOK)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Use(filesystem.New(filesystem.Config{
|
app.Get("/api/tags", func(c *fiber.Ctx) error {
|
||||||
Root: http.FS(f),
|
tags, err := GetScheduleTags(db)
|
||||||
PathPrefix: "public",
|
|
||||||
}))
|
if err != nil {
|
||||||
|
log.Printf("failed to find schedule tags: %v", err)
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(tags)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Post("/api/tags", func(c *fiber.Ctx) error {
|
||||||
|
input := new(NewScheduleTag)
|
||||||
|
|
||||||
|
if err := c.BodyParser(input); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.Name == nil || len(*input.Name) == 0 {
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString("Name is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
tag, err := CreateScheduleTag(db, *input.Name)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to create schedule tag: %v", err)
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(tag)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Get("/api/tags/:id<int>", func(c *fiber.Ctx) error {
|
||||||
|
id, err := c.ParamsInt("id")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString("Invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
|
tag, err := GetScheduleTag(db, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to find schedule tag: %v", err)
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag == nil {
|
||||||
|
return c.SendStatus(fiber.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(*tag)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Delete("/api/tags/:id<int>", func(c *fiber.Ctx) error {
|
||||||
|
id, err := c.ParamsInt("id")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).SendString("Invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := DeleteScheduleTag(db, id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to delete schedule item: %v", err)
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return c.SendStatus(fiber.StatusNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(http.StatusOK)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Use(filesystem.New(filesystem.Config{
|
||||||
|
Root: http.FS(f),
|
||||||
|
PathPrefix: "public",
|
||||||
|
}))
|
||||||
|
|
||||||
log.Fatal(app.Listen(":3000"))
|
log.Fatal(app.Listen(":3000"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
|
||||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Schedule</title>
|
|
||||||
<script type="module" crossorigin src="/assets/index-b0266e6c.js"></script>
|
|
||||||
<link rel="stylesheet" href="/assets/index-7823ff9f.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in a new issue