Initial commit

main
Antonio De Lucreziis 2 years ago
commit 830bbf7e1f

11
.gitignore vendored

@ -0,0 +1,11 @@
.env
*.local*
node_modules/
bin/
.out/
out/
dist/
.vscode/

@ -0,0 +1,20 @@
NPM = pnpm
.PHONY: all
all: build-frontend build-backend
.PHONY: setup
setup:
mkdir -p out/frontend
mkdir -p out/backend
$(NPM) install
.PHONY: build-frontend
build-frontend:
$(NPM) run build
.PHONY: build-backend
build-backend:
go build -v -o out/backend/server ./cmd/server

@ -0,0 +1,23 @@
# Knot Toolbox
A knot web tool to work and share knots
## Usage
### Development
The following command will start the backend (by default on `:4000`) and the ViteJS development server (by default on `:3000`).
```bash shell
$ go run -v ./cmd/develop
```
### Production
```bash shell
$ npm run build
$ go run -v ./cmd/server
# or just run...
$ make
```

@ -0,0 +1,3 @@
package backend
type Database interface{}

@ -0,0 +1 @@
package config

@ -0,0 +1,3 @@
package database
type Mem struct{}

@ -0,0 +1,14 @@
package server
import (
"aziis98.com/template-go-vitejs/backend"
"github.com/gofiber/fiber/v2"
)
func registerRoutes(r fiber.Router, db backend.Database) {
r.Get("/", func(c *fiber.Ctx) error {
return c.SendFile("./out/frontend/index.html")
})
r.Static("/", "./out/frontend")
}

@ -0,0 +1,18 @@
package server
import (
"aziis98.com/template-go-vitejs/backend"
"github.com/gofiber/fiber/v2"
)
type Dependencies struct {
DB backend.Database
}
func New(deps Dependencies) *fiber.App {
app := fiber.New()
registerRoutes(app, deps.DB)
return app
}

@ -0,0 +1,43 @@
package main
import (
"bufio"
"io"
"log"
"os/exec"
"aziis98.com/template-go-vitejs/backend/database"
"aziis98.com/template-go-vitejs/backend/server"
"golang.org/x/sync/errgroup"
)
func main() {
srv := server.New(server.Dependencies{
DB: &database.Mem{},
})
g := &errgroup.Group{}
g.Go(func() error {
log.Printf(`[develop] listening on port :4000...`)
return srv.Listen(":4000")
})
g.Go(func() error {
log.Printf(`[develop] starting vitejs development server...`)
r, w := io.Pipe()
cmd := exec.Command("npm", "run", "dev")
cmd.Stdout = w
stdout := bufio.NewScanner(r)
go func() {
for stdout.Scan() {
log.Printf(`[develop] [vitejs] %s`, stdout.Text())
}
}()
return cmd.Run()
})
log.Fatal(g.Wait())
}

@ -0,0 +1,16 @@
package main
import (
"log"
"aziis98.com/template-go-vitejs/backend/database"
"aziis98.com/template-go-vitejs/backend/server"
)
func main() {
srv := server.New(server.Dependencies{
DB: &database.Mem{},
})
log.Fatal(srv.Listen(":4000"))
}

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<link rel="stylesheet" href="/styles/main.scss">
<title>Knot ToolBox</title>
</head>
<body>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

@ -0,0 +1,25 @@
function distance([x1, y1], [x2, y2]) {
return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
}
export function simplifyCurve(curve, minDistance) {
if (curve.length === 0) return []
const newCurve = [curve[0]]
let lastPt = curve[0]
for (let i = 1; i < curve.length; i++) {
const pt = curve[i]
if (distance(lastPt, pt) >= minDistance) {
newCurve.push(pt)
lastPt = pt
}
}
if (lastPt !== curve.at(-1)) {
newCurve.push(curve.at(-1))
}
return newCurve
}

@ -0,0 +1,128 @@
console.clear()
function splitStringAtSeparator(str, separator) {
const separatorIndex = str.indexOf(separator)
if (separatorIndex === -1) {
return [str, '']
} else {
const beforeSeparator = str.slice(0, separatorIndex)
const afterSeparator = str.slice(separatorIndex + separator.length)
return [beforeSeparator, afterSeparator]
}
}
const REGISTRY = {}
const compileNewVector = (length, params, componentFn) => {
const label = `vector<${length}>(${componentFn.toString()})`
// console.log(`requested function for "${label}"`)
let fn = REGISTRY[label]
if (!fn) {
const [varsRaw, codeRaw] = splitStringAtSeparator(componentFn.toString(), '=>')
const freeIndex = varsRaw.replace(/[()]/g, '').trim()
const code = codeRaw.trim()
// console.log('compiling...')
let source = `const out = Array(${length});\n`
for (let i = 0; i < length; i++) {
source += `out[${i}] = ${code.replaceAll(freeIndex, i)};\n`
}
source += `return out;`
// console.log(`=> Source: "${source.replaceAll('\n', ' ')}"`)
fn = new Function(...Object.keys(params), source)
REGISTRY[label] = fn
} else {
// console.log('using cached')
}
return fn(...Object.values(params))
}
const compileSum = (length, params, componentFn) => {
const label = `sum<${length}>(${componentFn.toString()})`
// console.log(`requested function for "${label}"`)
let fn = REGISTRY[label]
if (!fn) {
const [varsRaw, codeRaw] = splitStringAtSeparator(componentFn.toString(), '=>')
const freeIndex = varsRaw.replace(/[()]/g, '').trim()
const code = codeRaw.trim()
// console.log('compiling...')
let source = `let out = 0;\n`
for (let i = 0; i < length; i++) {
source += `out += ${code.replaceAll(freeIndex, i)};\n`
}
source += `return out;`
// console.log(`=> Source: "${source.replaceAll('\n', ' ')}"`)
fn = new Function(...Object.keys(params), source)
REGISTRY[label] = fn
} else {
// console.log('using cached')
}
return fn(...Object.values(params))
}
const operators = {
['+'](v, w) {
return compileNewVector(v.length, { v, w }, i => v[i] + w[i])
},
['*'](v, w) {
return compileNewVector(v.length, { v, w }, i => v[i] * w[i])
},
['-'](v, w) {
return compileNewVector(v.length, { v, w }, i => v[i] - w[i])
},
['/'](v, w) {
return compileNewVector(v.length, { v, w }, i => v[i] / w[i])
},
['dot'](v, w) {
const vw = operators['*'](v, w)
return compileSum(v.length, { vw }, i => vw[i])
},
}
export const m = (fragments, ...args) => {
const opName = fragments[1].trim()
return operators[opName](...args)
}
const v1 = [1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3]
const w1 = [2, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4]
const v2 = [1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3]
const w2 = [2, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4]
function dotVectors(v, w) {
return v.map((vi, i) => vi * w[i]).reduce((acc, vw) => acc + vw, 0)
}
// Benchmarking code
const iterations = 50000
for (let i = 0; i < 10; i++) {
const start = performance.now()
let result
for (let i = 0; i < iterations; i++) {
result = i % 2 === 0 ? m`${v1} dot ${w1}` : m`${v2} dot ${w2}`
}
const end = performance.now()
console.log(`Time for ${iterations} iterations: ${end - start}ms`)
}
console.log('----------')
for (let i = 0; i < 10; i++) {
const start = performance.now()
let result
for (let i = 0; i < iterations; i++) {
result = i % 2 === 0 ? dotVectors(v1, w1) : dotVectors(v2, w2)
}
const end = performance.now()
console.log(`Time for ${iterations} iterations: ${end - start}ms`)
}

@ -0,0 +1,120 @@
import { useEffect, useRef, useState } from 'preact/hooks'
import { simplifyCurve } from '../../lib/math/curves.js'
class KnotSimulation {
constructor(knotRef) {
this.knotRef = knotRef
this.ghostPath = null
}
onMouseDrag(x, y) {
if (!this.ghostPath) {
this.ghostPath = []
}
this.ghostPath.push([x, y])
}
onMouseUp() {
this.knotRef.current.points = simplifyCurve(this.ghostPath, 15)
this.ghostPath = null
}
update() {}
/** @param {CanvasRenderingContext2D} g */
render(g) {
const w = g.canvas.width
const h = g.canvas.height
const knot = this.knotRef.current
g.clearRect(0, 0, w, h)
g.lineWidth = 3
g.lineCap = 'round'
g.lineJoin = 'round'
g.strokeStyle = '#333'
if (this.ghostPath && this.ghostPath.length > 0) {
g.strokeStyle = '#888'
g.beginPath()
{
const [x0, y0] = this.ghostPath[0]
g.moveTo(x0, y0)
for (const [x, y] of this.ghostPath) {
g.lineTo(x, y)
}
}
g.stroke()
} else if (knot.points.length > 0) {
g.beginPath()
const [x0, y0] = knot.points[0]
g.moveTo(x0, y0)
for (const [x, y] of knot.points) {
g.lineTo(x, y)
}
g.stroke()
g.fillStyle = '#080'
for (const [x, y] of knot.points) {
g.beginPath()
g.ellipse(x, y, 3, 3, 0, 0, Math.PI * 2)
g.fill()
}
}
}
}
export const KnotLayer = ({ knotRef }) => {
const canvasRef = useRef(null)
const [knotSim] = useState(() => new KnotSimulation(knotRef))
useEffect(() => {
window.addEventListener('resize', () => {
// trigger repaint and get a new context
})
}, [])
useEffect(() => {
let simTimerHandle
if (canvasRef.current) {
canvasRef.current.width = canvasRef.current.offsetWidth
canvasRef.current.height = canvasRef.current.offsetHeight
const g = canvasRef.current.getContext('2d')
simTimerHandle = setInterval(() => {
knotSim.update()
requestAnimationFrame(() => knotSim.render(g))
console.log('Prova')
}, 1000 / 30)
}
return () => {
if (simTimerHandle) {
clearInterval(simTimerHandle)
}
}
}, [canvasRef.current])
return (
<canvas
ref={canvasRef}
onMouseDown={e => {
if (e.buttons === 1) {
knotSim.onMouseDrag(e.offsetX, e.offsetY)
}
}}
onMouseMove={e => {
if (e.buttons === 1) {
knotSim.onMouseDrag(e.offsetX, e.offsetY)
}
}}
onMouseUp={e => {
knotSim.onMouseUp()
}}
/>
)
}

@ -0,0 +1,24 @@
import { Router, route } from 'preact-router'
import { render } from 'preact'
import { useEffect } from 'preact/hooks'
import { PageHomepage, PageKnotEditor } from './pages.jsx'
const Redirect = ({ to }) => {
useEffect(() => {
route(to, true)
}, [])
return null
}
const Main = ({}) => {
return (
<Router>
<PageHomepage path="/" />
<PageKnotEditor path="/knot/new" />
<Redirect default to="/" />
</Router>
)
}
render(<Main />, document.body)

@ -0,0 +1,93 @@
import { useRef } from 'preact/hooks'
import { KnotLayer } from './components/KnotLayer.jsx'
export const PageHomepage = ({}) => {
return (
<main>
<h1>Homepage</h1>
</main>
)
}
export const PageKnotEditor = ({}) => {
const knot1 = useRef({
points: [],
})
return (
<main>
<div class="toolbar">
<div class="logo">
<span class="material-symbols-outlined">home_repair_service</span>
Knot ToolBox
</div>
<div class="group">
<div class="label">Tools</div>
<div class="content">
<div class="compound-select">
<button class="icon selected">
<span class="material-symbols-outlined">gesture</span>
</button>
<button class="icon">
<span class="material-symbols-outlined">swap_vert</span>
</button>
<button class="icon">
<span class="material-symbols-outlined">pinch</span>
</button>
</div>
</div>
</div>
<div class="group">
<div class="label">Library</div>
<div class="content">
<button class="icon">
<span class="material-symbols-outlined">search</span>
</button>
<button class="icon">
<span class="material-symbols-outlined">bookmark_add</span>
</button>
</div>
</div>
</div>
<div class="outline">
<div class="layer">
<div class="name">
<span class="material-symbols-outlined">layers</span>
Layer 1
</div>
<div class="buttons">
<button class="flat icon small">
<span class="material-symbols-outlined">edit</span>
</button>
</div>
</div>
<div class="layer">
<div class="name">
<span class="material-symbols-outlined">layers</span>
Layer 2
</div>
<div class="buttons">
<button class="flat icon small">
<span class="material-symbols-outlined">edit</span>
</button>
</div>
</div>
<div class="layer">
<div class="name">
<span class="material-symbols-outlined">layers</span>
Layer 3
</div>
<div class="buttons">
<button class="flat icon small">
<span class="material-symbols-outlined">edit</span>
</button>
</div>
</div>
</div>
<div class="work-area">
<KnotLayer knotRef={knot1} />
</div>
</main>
)
}

@ -0,0 +1,235 @@
*,
*::before,
*::after {
// Good practice
box-sizing: border-box;
// For body and headings as typography should be done by hand anyway
margin: 0;
// For controls
font-family: inherit;
appearance: none;
}
html,
body {
display: contents;
font-family: 'Inter', sans-serif;
font-weight: 400;
font-size: 16px;
background: #f4f4f4;
color: #333;
}
// Headings
$base-font-size: 15px;
$heading-scale: 1.33;
@function pow($number, $exponent) {
$value: 1;
@if $exponent > 0 {
@for $i from 1 through $exponent {
$value: $value * $number;
}
}
@return $value;
}
@for $i from 1 through 5 {
h#{$i} {
font-family: 'Inter', sans-serif;
font-weight: 500;
$factor: pow($heading-scale, 5 - $i);
font-size: $base-font-size * $factor;
}
}
// Controls
button {
border: 1px solid #d0d0d0;
background: #fff;
font-size: 15px;
border-radius: 6px;
cursor: pointer;
&.flat {
border-color: transparent;
background-color: transparent;
&:hover {
background: #d0d0d0;
}
}
&.icon {
aspect-ratio: 1;
display: grid;
place-content: center;
}
display: flex;
align-items: center;
gap: 0.25rem;
height: 2rem;
.material-symbols-outlined {
font-size: 20px;
}
&.small {
height: 1.5rem;
.material-symbols-outlined {
font-size: 16px;
}
}
}
.compound-select {
display: flex;
flex-direction: row;
gap: 0.25rem;
button.selected {
background: #f0f0f0;
border-color: #888;
}
}
// Structure
main {
user-select: none;
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: 10rem 1fr;
grid-template-rows: auto 1fr;
grid-template-areas:
'toolbar toolbar'
'outline work-area';
.toolbar {
grid-area: toolbar;
background: #fff;
border-bottom: 1px solid #d0d0d0;
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
padding: 0.5rem 1rem;
.logo {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 22px;
font-weight: 500;
padding-right: 0.5rem;
}
.group {
display: flex;
flex-direction: column;
gap: 0.25rem;
.label {
font-size: 13px;
color: #333;
font-weight: 300;
}
.content {
display: flex;
flex-direction: row;
gap: 0.25rem;
}
}
}
.outline {
grid-area: outline;
padding: 0.5rem;
display: flex;
flex-direction: column;
gap: 0.25rem;
background: #fff;
border-right: 1px solid #d0d0d0;
.layer {
padding: 0 0 0 0.25rem;
height: 1.5rem;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: space-between;
.name {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: 15px;
.material-symbols-outlined {
font-size: 18px;
}
}
.buttons {
display: flex;
align-items: center;
flex-direction: row;
gap: 0.25rem;
}
&:not(:hover) {
.buttons {
display: none;
}
}
&:hover {
background: #f0f0f0;
}
}
}
.work-area {
grid-area: work-area;
position: relative;
canvas {
position: absolute;
width: 100%;
height: 100%;
}
}
}

@ -0,0 +1,26 @@
module aziis98.com/template-go-vitejs
go 1.19
require (
github.com/gofiber/fiber/v2 v2.42.0
golang.org/x/sync v0.1.0
)
require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/philhofer/fwd v1.1.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/tinylib/msgp v1.1.6 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.44.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
)

@ -0,0 +1,67 @@
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/gofiber/fiber/v2 v2.42.0 h1:Fnp7ybWvS+sjNQsFvkhf4G8OhXswvB6Vee8hM/LyS+8=
github.com/gofiber/fiber/v2 v2.42.0/go.mod h1:3+SGNjqMh5VQH5Vz2Wdi43zTIV16ktlFd3x3R6O1Zlc=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo=
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw=
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q=
github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

@ -0,0 +1,21 @@
{
"name": "frontend",
"type": "module",
"scripts": {
"dev": "vite --clearScreen false",
"build": "vite build"
},
"author": "aziis98 <antonio.delucreziis@gmail.com>",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.21.0",
"@preact/preset-vite": "^2.5.0",
"sass": "^1.58.3",
"vite": "^4.1.4"
},
"dependencies": {
"axios": "^1.3.4",
"preact": "^10.13.0",
"preact-router": "^4.1.0"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,16 @@
import preactPlugin from '@preact/preset-vite'
import { defineConfig } from 'vite'
export default defineConfig({
root: 'frontend/',
build: {
outDir: '../out/frontend/',
},
server: {
port: 3000,
proxy: {
'/api': 'http://localhost:4000/',
},
},
plugins: [preactPlugin()],
})
Loading…
Cancel
Save