This commit is contained in:
2026-01-13 01:38:15 -05:00
parent b67235b93d
commit d9db2a771d
10 changed files with 334 additions and 0 deletions

5
.gitignore vendored
View File

@@ -45,6 +45,11 @@ go.work.sum
!*.go
!go.sum
!go.mod
!Dockerfile
!docker-compose.yaml
!air.toml
!*.html
!*.md
!README.md
!LICENSE

24
Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
# Use the official Golang image as the base.
FROM golang:1.22-alpine AS base
# Install git (required by go modules) and any other utilities.
RUN apk add --no-cache git
# Set the working directory inside the container.
WORKDIR /app
# Cache go.mod and go.sum to speed up dependency installation.
COPY go.mod go.sum ./
RUN go mod download
# Copy the rest of the source code.
COPY . .
# Build the binary after copying the source files.
RUN go build -o /app/tmp/main ./cmd/app
# The container will start Air, which watches the source files and rebuilds the app on change.
CMD ["./tmp/main"]

11
docker-compose.yaml Normal file
View File

@@ -0,0 +1,11 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
- GO111MODULE=on
command: ["./tmp/main"]

View File

@@ -0,0 +1,101 @@
# Agent Guide FrontEnd Web Components
## Purpose
This guide defines the conventions we follow for building the frontend of the **drawtools** project using **custom HTML web components**.
## Rules
1. **Only custom web components**
- All UI elements must be implemented as native HTML custom elements (`<mycomponent>`).
- No thirdparty UI libraries (e.g., React, Vue) are used.
2. **Selfcontained components**
- Each component lives in its own folder under `static/components`.
- The folder contains:
- `my-component.html` the HTML template (including `<template>` tag).
- `my-component.js` the class definition that registers the element.
- Optional `my-component.css` scoped styles imported by the HTML template.
- `README.md` usage instructions and a changelog for that component.
3. **One markdown file per component**
- Inside each component folder, `README.md` documents:
- How to import the component in a page.
- Public attributes, properties, and events.
- Example markup.
- A chronological **Change Log** (date, author, description).
4. **Directory structure & naming**
```
draw-tools/
└─ static/
└─ components/
├─ my-button/
│ ├─ my-button.html
│ ├─ my-button.js
│ ├─ my-button.css (optional)
│ └─ README.md
├─ my-card/
│ └─ … (same pattern)
└─ AGENT_GUIDE.md ← this file
```
- Folder name = kebabcase version of the component name.
- File names match the component name (e.g., `my-button.html`).
5. **Component registration**
```js
class MyButton extends HTMLElement {
constructor() { super(); /* … */ }
/* lifecycle callbacks, methods, etc. */
}
customElements.define('my-button', MyButton);
```
- The registration must happen **once** per component (usually at the end of the `.js` file).
6. **Styling**
- Use the Shadow DOM to encapsulate styles.
- If a separate `.css` file is present, import it inside the HTML template:
```html
<style>@import "./my-button.css";</style>
```
7. **Documentation updates**
- Whenever a component is added, modified, or removed, update its `README.md` and the **Change Log** section at the bottom of the file.
- Keep this `AGENT_GUIDE.md` uptodate with any new rules.
## Example Component Layout
```
static/components/my-button/
├─ my-button.html ← <template> with markup and optional <style>
├─ my-button.js ← class definition + registration
├─ my-button.css ← (optional) scoped CSS
└─ README.md ← usage guide & change log
```
### Sample `README.md` (inside `my-button`)
```markdown
# MyButton Component
## Usage
```html
<script type="module" src="/static/components/my-button/my-button.js"></script>
<my-button label="Click me"></my-button>
```
## Attributes / Properties
- `label` (string) Text displayed inside the button.
## Events
- `click` dispatched when the button is pressed.
## Change Log
| Date | Author | Change |
|------------|--------|--------|
| 20260111 | Thomas | Initial creation |
```
---
**Keep this guide** in the repo root of the components folder so any new team member can quickly understand the structure and expectations.

View File

@@ -0,0 +1,38 @@
<template id="canvas-display-template">
<style></style>
:host {
display: block;
position: relative;
font-family: sans-serif;
}
.canvas-wrapper {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
canvas {
display: block;
width: 100%;
height: 100%;
background: var(--bg-color, #ffffff);
}
/* grid overlay */
.grid-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
</style>
<div class="canvas-wrapper">
<canvas id="draw-canvas"></canvas>
<svg class="grid-overlay" id="grid-overlay"></svg>
</div>
</template>

View File

@@ -0,0 +1,29 @@
<template id="color-picker-template">
<style></style>
:host {
display: inline-block;
font-family: sans-serif;
}
.wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
}
input[type="color"] {
border: none;
width: 2rem;
height: 2rem;
padding: 0;
background: none;
}
label {
font-size: 0.9rem;
user-select: none;
}
</style>
<div class="wrapper">
<label for="color-input">Background:</label>
<input type="color" id="color-input" value="#ffffff">
</div>
</template>

View File

@@ -0,0 +1,41 @@
<template id="grid-selector-template">
<style></style>
:host {
display: inline-block;
font-family: sans-serif;
}
.wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
}
label {
font-size: 0.9rem;
user-select: none;
}
input[type="color"],
input[type="number"] {
border: none;
padding: 0;
background: none;
}
input[type="checkbox"] {
margin: 0;
}
</style>
<div class="wrapper">
<label for="grid-color">Grid color:</label>
<input type="color" id="grid-color" value="#000000">
<label for="grid-size">Size:</label>
<input type="number" id="grid-size" min="5" step="5" value="25">
<label for="grid-numbering">Numbering:</label>
<input type="checkbox" id="grid-numbering" checked>
</div>
</template>

View File

@@ -0,0 +1,43 @@
<template id="side-menu-template">
<style></style>
:host {
display: block;
width: var(--side-menu-width, 250px);
height: 100%;
background: var(--side-menu-bg, #f9f9f9);
border-right: 1px solid #ccc;
box-sizing: border-box;
position: relative;
transition: transform 0.3s ease;
}
.menu {
height: 100%;
overflow-y: auto;
}
.toggle {
position: absolute;
top: 0.5rem;
right: -1.5rem;
background: var(--toggle-bg, #f0f0f0);
border: 1px solid #ccc;
border-left: none;
border-radius: 0 4px 4px 0;
padding: 0.25rem 0.5rem;
cursor: pointer;
user-select: none;
}
.collapsed {
transform: translateX(-100%);
}
</style>
<div class="toggle" part="toggle"></div>
<nav class="menu" part="menu">
<slot></slot>
<color-picker></color-picker>
<label id="grid-toggle-label"><input type="checkbox" id="grid-toggle"> Grid</label>
</nav>
</template>

View File

@@ -0,0 +1,42 @@
<template id="toolbar-template">
<style></style>
:host {
display: block;
width: 100%;
background: #f0f0f0;
border-bottom: 1px solid #ccc;
box-sizing: border-box;
font-family: sans-serif;
}
.toolbar {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.5rem 1rem;
}
.section {
display: flex;
align-items: center;
gap: 0.5rem;
}
.section > label {
font-size: 0.9rem;
user-select: none;
}
</style>
<div class="toolbar">
<div class="section" id="bg-section">
<label for="bg-picker">Background:</label>
<slot name="bg-picker"></slot>
</div>
<div class="section" id="grid-section">
<label for="grid-picker">Grid:</label>
<slot name="grid-picker"></slot>
</div>
</div>
</template>

0
static/index.html Normal file
View File