summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarin Ivanov <[email protected]>2026-01-16 21:16:51 +0200
committerMarin Ivanov <[email protected]>2026-01-16 21:16:51 +0200
commit83be91046c188646205edf54f9570e009cb3bd43 (patch)
treef55e0e82f0acc7f26fc9b3a058edde698ed614b5
parent4dae24663a406f743f35ef70c4ea35a0578f55dd (diff)
paste images into form
-rw-r--r--form.html213
-rw-r--r--main.go19
-rw-r--r--post.html31
3 files changed, 220 insertions, 43 deletions
diff --git a/form.html b/form.html
new file mode 100644
index 0000000..a5de342
--- /dev/null
+++ b/form.html
@@ -0,0 +1,213 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Gloginki</title>
+
+ <style>
+ :root {
+ --bg: #f6f8fa;
+ --card-bg: #ffffff;
+ --border: #d0d7de;
+ --text: #24292f;
+ --muted: #57606a;
+ --primary: #2da44e;
+ --primary-hover: #2c974b;
+ --danger: #cf222e;
+ --radius: 6px;
+ }
+
+ * {
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
+ Helvetica, Arial, sans-serif;
+ }
+
+ body {
+ margin: 0;
+ padding: 2rem;
+ background: var(--bg);
+ color: var(--text);
+ }
+
+ h1 {
+ margin-bottom: 1rem;
+ font-size: 1.6rem;
+ }
+
+ .container {
+ max-width: 900px;
+ margin: 0 auto;
+ }
+
+ #error {
+ color: var(--danger);
+ margin-bottom: 1rem;
+ font-weight: 500;
+ }
+
+ form {
+ background: var(--card-bg);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ padding: 1.5rem;
+ margin-bottom: 2rem;
+ }
+
+ fieldset {
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ padding: 1rem;
+ margin-bottom: 1.2rem;
+ }
+
+ legend {
+ padding: 0 0.5rem;
+ color: var(--muted);
+ font-size: 0.9rem;
+ }
+
+ textarea {
+ width: 100%;
+ min-height: 250px;
+ resize: vertical;
+ padding: 0.75rem;
+ border-radius: var(--radius);
+ border: 1px solid var(--border);
+ font-size: 0.95rem;
+ }
+
+ textarea:focus,
+ input:focus {
+ outline: none;
+ border-color: #0969da;
+ }
+
+ input[type="file"],
+ input[type="text"] {
+ margin-top: 0.5rem;
+ }
+
+ .submit-row {
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+ flex-wrap: wrap;
+ }
+
+ input[type="submit"] {
+ background: var(--primary);
+ color: white;
+ border: none;
+ padding: 0.6rem 1.2rem;
+ border-radius: var(--radius);
+ font-weight: 600;
+ cursor: pointer;
+ }
+
+ input[type="submit"]:hover {
+ background: var(--primary-hover);
+ }
+
+ /* Preview card */
+ #preview-container {
+ background: var(--card-bg);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ padding: 1rem;
+ }
+
+ #preview-container h2 {
+ margin-top: 0;
+ font-size: 1rem;
+ color: var(--muted);
+ }
+
+ #preview {
+ max-width: 100%;
+ border-radius: var(--radius);
+ display: none;
+ }
+
+ .hint {
+ font-size: 0.85rem;
+ color: var(--muted);
+ margin-top: 0.5rem;
+ }
+ </style>
+</head>
+
+<body>
+ <div class="container">
+ <h1>Bin-ки и глогинки.</h1>
+
+ <div id="error"></div>
+
+ <form enctype="multipart/form-data" action="/post" method="post">
+ <fieldset>
+ <legend>Text Posting</legend>
+ <textarea name="text" placeholder="Write something..."></textarea>
+ </fieldset>
+
+ <fieldset>
+ <legend>File Upload</legend>
+ <input type="file" name="file" />
+ <div class="hint">You can also paste an image directly</div>
+ </fieldset>
+
+ <fieldset>
+ <legend>Submit</legend>
+ <div class="submit-row">
+ <label>
+ Mime-type:
+ <input type="text" name="mimetype" value="auto" />
+ </label>
+ <input type="submit" value="Post" />
+ </div>
+ </fieldset>
+ </form>
+
+ <div id="preview-container">
+ <h2>Image Preview</h2>
+ <img id="preview" />
+ <div class="hint" id="preview-hint">Paste an image to preview it</div>
+ </div>
+ </div>
+
+ <script>
+ const pasteArea = document.body;
+ const preview = document.getElementById("preview");
+ const previewHint = document.getElementById("preview-hint");
+ const form = document.querySelector("form");
+
+ let pastedFile = null;
+
+ pasteArea.addEventListener("paste", (event) => {
+ const items = event.clipboardData.items;
+
+ for (const item of items) {
+ if (item.type.startsWith("image/")) {
+ pastedFile = item.getAsFile();
+
+ preview.src = URL.createObjectURL(pastedFile);
+ preview.style.display = "block";
+ previewHint.style.display = "none";
+
+ event.preventDefault();
+ break;
+ }
+ }
+ });
+
+ form.addEventListener("submit", () => {
+ if (pastedFile) {
+ const fileInput = form.querySelector('input[type="file"]');
+ const dt = new DataTransfer();
+ dt.items.add(pastedFile);
+ fileInput.files = dt.files;
+ }
+ });
+ </script>
+</body>
+</html>
diff --git a/main.go b/main.go
index 2ed8b93..c4bf010 100644
--- a/main.go
+++ b/main.go
@@ -33,7 +33,7 @@ type Metadata struct {
ContentType string `json:"contentType"`
}
-//go:embed post.html
+//go:embed form.html
var static embed.FS
func detectMimetype(input io.Reader) (mimeType string, fileext string, recycled io.Reader, err error) {
@@ -158,13 +158,6 @@ func (s *Server) formPost(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusFound)
}
-func (s *Server) formGet(w http.ResponseWriter, r *http.Request) {
- f, _ := static.Open("post.html")
- if _, err := io.Copy(w, f); err != nil {
- w.WriteHeader(http.StatusInternalServerError)
- }
-}
-
func (s *Server) servePosting(w http.ResponseWriter, r *http.Request, name string) {
filename := filepath.Join(s.data, name)
m, err := readMetadata(filename + MetadataExt)
@@ -240,8 +233,11 @@ func (s *Server) indexPost(w http.ResponseWriter, r *http.Request) {
func (s *Server) indexGet(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if path == "/" {
- w.Header().Add("content-type", "text/plain; charset=UTF-8")
- w.Write([]byte("Bin-ки и глогинки."))
+ w.Header().Add("content-type", "text/html; charset=UTF-8")
+ f, _ := static.Open("form.html")
+ if _, err := io.Copy(w, f); err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ }
} else {
s.servePosting(w, r, filepath.Base(path))
}
@@ -249,11 +245,10 @@ func (s *Server) indexGet(w http.ResponseWriter, r *http.Request) {
func (s *Server) Post(w http.ResponseWriter, r *http.Request) {
switch r.Method {
- case http.MethodGet:
- s.formGet(w, r)
case http.MethodPost:
s.formPost(w, r)
default:
+ w.WriteHeader(http.StatusBadRequest)
}
}
diff --git a/post.html b/post.html
deleted file mode 100644
index 3ed8f1b..0000000
--- a/post.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <meta http-equiv="X-UA-Compatible" content="ie=edge" />
- <title>Gloginki</title>
- </head>
- <body>
- <form
- enctype="multipart/form-data"
- action="/post"
- method="post"
- >
- <fieldset>
- <legend>Text Posting</legend>
- <textarea name="text" style="width:100%;min-height:300px;"></textarea>
- </fieldset>
- <fieldset>
- <legend>File Upload</legend>
- <input type="file" name="file" />
- </fieldset>
- <fieldset>
- <legend>Submit</legend>
- <label for="mimetype">Mime-type:</label>
- <input type="text" name="mimetype" value="auto" />
- <input type="submit" value="Post" />
- </fieldset>
- </form>
- </body>
-</html> \ No newline at end of file