Compare commits
10 Commits
79f64f6016
...
e6b9ed1c5d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6b9ed1c5d | ||
|
|
0bd39683ff | ||
|
|
914138b221 | ||
|
|
c4b4c22310 | ||
|
|
852b2c3f4d | ||
|
|
56e6d9f391 | ||
|
|
15eb2512b0 | ||
|
|
6e1a25b5d6 | ||
|
|
44fd876044 | ||
|
|
cabc17cf09 |
@@ -21,7 +21,7 @@ ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
|
||||
FROM ${BUILDER_IMAGE} AS builder
|
||||
|
||||
# install build dependencies
|
||||
RUN apt-get update -y && apt-get install -y build-essential git imagemagick \
|
||||
RUN apt-get update -y && apt-get install -y build-essential git imagemagick fonts-dejavu fonts-liberation fonts-freefont-ttf \
|
||||
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
|
||||
|
||||
# Debian version still uses 'convert'
|
||||
@@ -71,7 +71,7 @@ RUN mix release
|
||||
FROM ${RUNNER_IMAGE}
|
||||
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y libstdc++6 openssl libncurses5 locales ca-certificates imagemagick \
|
||||
apt-get install -y libstdc++6 openssl libncurses5 locales ca-certificates imagemagick fonts-dejavu fonts-liberation fonts-freefont-ttf \
|
||||
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
|
||||
|
||||
# Debian version still uses 'convert'
|
||||
|
||||
@@ -16,29 +16,24 @@
|
||||
//
|
||||
|
||||
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
|
||||
import "phoenix_html"
|
||||
import 'phoenix_html';
|
||||
// Establish Phoenix Socket and LiveView configuration.
|
||||
import {Socket} from "phoenix"
|
||||
import {LiveSocket} from "phoenix_live_view"
|
||||
import topbar from "../vendor/topbar"
|
||||
import { Socket } from 'phoenix';
|
||||
import { LiveSocket } from 'phoenix_live_view';
|
||||
import Hooks from './hooks';
|
||||
|
||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
|
||||
let liveSocket = new LiveSocket("/live", Socket, {
|
||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute('content');
|
||||
let liveSocket = new LiveSocket('/live', Socket, {
|
||||
hooks: Hooks,
|
||||
longPollFallbackMs: 2500,
|
||||
params: {_csrf_token: csrfToken}
|
||||
})
|
||||
|
||||
// Show progress bar on live navigation and form submits
|
||||
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
|
||||
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
|
||||
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())
|
||||
params: { _csrf_token: csrfToken },
|
||||
});
|
||||
|
||||
// connect if there are any LiveViews on the page
|
||||
liveSocket.connect()
|
||||
liveSocket.connect();
|
||||
|
||||
// expose liveSocket on window for web console debug logs and latency simulation:
|
||||
// >> liveSocket.enableDebug()
|
||||
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
|
||||
// >> liveSocket.disableLatencySim()
|
||||
window.liveSocket = liveSocket
|
||||
|
||||
window.liveSocket = liveSocket;
|
||||
|
||||
52
assets/js/hooks.js
Normal file
52
assets/js/hooks.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const Hooks = {
|
||||
EnterToNewline: {
|
||||
mounted() {
|
||||
this.el.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
|
||||
const cursorPos = this.el.selectionStart;
|
||||
const value = this.el.value;
|
||||
|
||||
this.el.value = value.slice(0, cursorPos) + '\\n' + value.slice(cursorPos);
|
||||
this.el.selectionStart = this.el.selectionEnd = cursorPos + 2;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
PersistData: {
|
||||
mounted() {
|
||||
const form = this.el;
|
||||
const key = 'label';
|
||||
const stored = JSON.parse(localStorage.getItem(key) || '{}');
|
||||
|
||||
let updated = false;
|
||||
|
||||
for (let [name, value] of Object.entries(stored)) {
|
||||
const input = form.querySelector(`[name="${name}"]`);
|
||||
|
||||
if (input) {
|
||||
input.value = value;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
this.pushEvent('update_label', stored);
|
||||
}
|
||||
|
||||
form.addEventListener('input', () => {
|
||||
const data = {};
|
||||
|
||||
for (let el of form.elements) {
|
||||
if (el.name) data[el.name] = el.value;
|
||||
}
|
||||
|
||||
localStorage.setItem(key, JSON.stringify(data));
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default Hooks;
|
||||
165
assets/vendor/topbar.js
vendored
165
assets/vendor/topbar.js
vendored
@@ -1,165 +0,0 @@
|
||||
/**
|
||||
* @license MIT
|
||||
* topbar 2.0.0, 2023-02-04
|
||||
* https://buunguyen.github.io/topbar
|
||||
* Copyright (c) 2021 Buu Nguyen
|
||||
*/
|
||||
(function (window, document) {
|
||||
"use strict";
|
||||
|
||||
// https://gist.github.com/paulirish/1579671
|
||||
(function () {
|
||||
var lastTime = 0;
|
||||
var vendors = ["ms", "moz", "webkit", "o"];
|
||||
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||||
window.requestAnimationFrame =
|
||||
window[vendors[x] + "RequestAnimationFrame"];
|
||||
window.cancelAnimationFrame =
|
||||
window[vendors[x] + "CancelAnimationFrame"] ||
|
||||
window[vendors[x] + "CancelRequestAnimationFrame"];
|
||||
}
|
||||
if (!window.requestAnimationFrame)
|
||||
window.requestAnimationFrame = function (callback, element) {
|
||||
var currTime = new Date().getTime();
|
||||
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||||
var id = window.setTimeout(function () {
|
||||
callback(currTime + timeToCall);
|
||||
}, timeToCall);
|
||||
lastTime = currTime + timeToCall;
|
||||
return id;
|
||||
};
|
||||
if (!window.cancelAnimationFrame)
|
||||
window.cancelAnimationFrame = function (id) {
|
||||
clearTimeout(id);
|
||||
};
|
||||
})();
|
||||
|
||||
var canvas,
|
||||
currentProgress,
|
||||
showing,
|
||||
progressTimerId = null,
|
||||
fadeTimerId = null,
|
||||
delayTimerId = null,
|
||||
addEvent = function (elem, type, handler) {
|
||||
if (elem.addEventListener) elem.addEventListener(type, handler, false);
|
||||
else if (elem.attachEvent) elem.attachEvent("on" + type, handler);
|
||||
else elem["on" + type] = handler;
|
||||
},
|
||||
options = {
|
||||
autoRun: true,
|
||||
barThickness: 3,
|
||||
barColors: {
|
||||
0: "rgba(26, 188, 156, .9)",
|
||||
".25": "rgba(52, 152, 219, .9)",
|
||||
".50": "rgba(241, 196, 15, .9)",
|
||||
".75": "rgba(230, 126, 34, .9)",
|
||||
"1.0": "rgba(211, 84, 0, .9)",
|
||||
},
|
||||
shadowBlur: 10,
|
||||
shadowColor: "rgba(0, 0, 0, .6)",
|
||||
className: null,
|
||||
},
|
||||
repaint = function () {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = options.barThickness * 5; // need space for shadow
|
||||
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.shadowBlur = options.shadowBlur;
|
||||
ctx.shadowColor = options.shadowColor;
|
||||
|
||||
var lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
|
||||
for (var stop in options.barColors)
|
||||
lineGradient.addColorStop(stop, options.barColors[stop]);
|
||||
ctx.lineWidth = options.barThickness;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, options.barThickness / 2);
|
||||
ctx.lineTo(
|
||||
Math.ceil(currentProgress * canvas.width),
|
||||
options.barThickness / 2
|
||||
);
|
||||
ctx.strokeStyle = lineGradient;
|
||||
ctx.stroke();
|
||||
},
|
||||
createCanvas = function () {
|
||||
canvas = document.createElement("canvas");
|
||||
var style = canvas.style;
|
||||
style.position = "fixed";
|
||||
style.top = style.left = style.right = style.margin = style.padding = 0;
|
||||
style.zIndex = 100001;
|
||||
style.display = "none";
|
||||
if (options.className) canvas.classList.add(options.className);
|
||||
document.body.appendChild(canvas);
|
||||
addEvent(window, "resize", repaint);
|
||||
},
|
||||
topbar = {
|
||||
config: function (opts) {
|
||||
for (var key in opts)
|
||||
if (options.hasOwnProperty(key)) options[key] = opts[key];
|
||||
},
|
||||
show: function (delay) {
|
||||
if (showing) return;
|
||||
if (delay) {
|
||||
if (delayTimerId) return;
|
||||
delayTimerId = setTimeout(() => topbar.show(), delay);
|
||||
} else {
|
||||
showing = true;
|
||||
if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId);
|
||||
if (!canvas) createCanvas();
|
||||
canvas.style.opacity = 1;
|
||||
canvas.style.display = "block";
|
||||
topbar.progress(0);
|
||||
if (options.autoRun) {
|
||||
(function loop() {
|
||||
progressTimerId = window.requestAnimationFrame(loop);
|
||||
topbar.progress(
|
||||
"+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2)
|
||||
);
|
||||
})();
|
||||
}
|
||||
}
|
||||
},
|
||||
progress: function (to) {
|
||||
if (typeof to === "undefined") return currentProgress;
|
||||
if (typeof to === "string") {
|
||||
to =
|
||||
(to.indexOf("+") >= 0 || to.indexOf("-") >= 0
|
||||
? currentProgress
|
||||
: 0) + parseFloat(to);
|
||||
}
|
||||
currentProgress = to > 1 ? 1 : to;
|
||||
repaint();
|
||||
return currentProgress;
|
||||
},
|
||||
hide: function () {
|
||||
clearTimeout(delayTimerId);
|
||||
delayTimerId = null;
|
||||
if (!showing) return;
|
||||
showing = false;
|
||||
if (progressTimerId != null) {
|
||||
window.cancelAnimationFrame(progressTimerId);
|
||||
progressTimerId = null;
|
||||
}
|
||||
(function loop() {
|
||||
if (topbar.progress("+.1") >= 1) {
|
||||
canvas.style.opacity -= 0.05;
|
||||
if (canvas.style.opacity <= 0.05) {
|
||||
canvas.style.display = "none";
|
||||
fadeTimerId = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fadeTimerId = window.requestAnimationFrame(loop);
|
||||
})();
|
||||
},
|
||||
};
|
||||
|
||||
if (typeof module === "object" && typeof module.exports === "object") {
|
||||
module.exports = topbar;
|
||||
} else if (typeof define === "function" && define.amd) {
|
||||
define(function () {
|
||||
return topbar;
|
||||
});
|
||||
} else {
|
||||
this.topbar = topbar;
|
||||
}
|
||||
}.call(this, window, document));
|
||||
@@ -33,7 +33,7 @@ if config_env() == :prod do
|
||||
You can generate one by calling: mix phx.gen.secret
|
||||
"""
|
||||
|
||||
host = System.get_env("PHX_HOST") || "example.com"
|
||||
host = System.get_env("PHX_HOST") || "labelmaker.xyz"
|
||||
port = String.to_integer(System.get_env("PORT") || "4000")
|
||||
|
||||
config :labelmaker, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
defmodule LabelmakerWeb.Constants do
|
||||
@defaults %{
|
||||
label: "",
|
||||
link: "",
|
||||
font: "Helvetica",
|
||||
color: "black",
|
||||
outline: "white",
|
||||
@@ -8,14 +9,11 @@ defmodule LabelmakerWeb.Constants do
|
||||
}
|
||||
|
||||
@preview %{
|
||||
preview_bg: "r",
|
||||
preview_height: @defaults.size,
|
||||
preview_text: []
|
||||
}
|
||||
|
||||
@stringview @preview
|
||||
|> Enum.map(fn {k, v} -> {Atom.to_string(k), v} end)
|
||||
|> Map.new()
|
||||
|
||||
@permitted_keys @defaults
|
||||
|> Map.merge(@preview)
|
||||
|> Map.keys()
|
||||
@@ -27,6 +25,10 @@ defmodule LabelmakerWeb.Constants do
|
||||
# drop header stuff
|
||||
|> Enum.drop(5)
|
||||
|> Enum.map(fn color_info -> color_info |> String.split() |> List.first() end)
|
||||
|> Enum.reject(&is_nil/1)
|
||||
# filter out colors that end in a number (no CSS equivalent)
|
||||
|> Enum.reject(fn color -> String.match?(color, ~r/\d+$/) end)
|
||||
|> Enum.uniq()
|
||||
|
||||
@fonts System.cmd("magick", ["-list", "font"])
|
||||
|> elem(0)
|
||||
@@ -56,5 +58,4 @@ defmodule LabelmakerWeb.Constants do
|
||||
def permitted_keys, do: @permitted_keys
|
||||
def preview, do: @preview
|
||||
def sizes, do: @sizes
|
||||
def stringview, do: @stringview
|
||||
end
|
||||
|
||||
@@ -4,7 +4,6 @@ defmodule LabelmakerWeb.LabelController do
|
||||
alias LabelmakerWeb.Tools
|
||||
|
||||
@label_dir Path.join(:code.priv_dir(:labelmaker), "static/labels")
|
||||
File.mkdir_p!(@label_dir)
|
||||
|
||||
def show(conn, params) do
|
||||
options = Tools.process_parameters(params)
|
||||
@@ -28,6 +27,8 @@ defmodule LabelmakerWeb.LabelController do
|
||||
end
|
||||
|
||||
defp generate_image(options, filepath) do
|
||||
File.mkdir_p!(@label_dir)
|
||||
|
||||
args = [
|
||||
"-background",
|
||||
"none",
|
||||
|
||||
@@ -18,10 +18,16 @@ defmodule LabelmakerWeb.Home do
|
||||
}
|
||||
end
|
||||
|
||||
def handle_event("update_preview", %{"bg" => bg}, socket) do
|
||||
{:noreply, assign(socket, :preview_bg, bg)}
|
||||
end
|
||||
|
||||
def handle_event("update_label", params, socket) do
|
||||
assigns =
|
||||
params
|
||||
|> Map.merge(Constants.stringview())
|
||||
socket.assigns
|
||||
|> Enum.map(fn {k, v} -> {Atom.to_string(k), v} end)
|
||||
|> Map.new()
|
||||
|> Map.merge(params)
|
||||
|> Tools.process_parameters()
|
||||
|> Enum.to_list()
|
||||
|
||||
@@ -33,7 +39,20 @@ defmodule LabelmakerWeb.Home do
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
label_too_long = String.length(assigns.label) > Constants.max_label_length()
|
||||
preview_background =
|
||||
case assigns.preview_bg do
|
||||
"r" -> "bg-[linear-gradient(to_right,_black_33%,_white_67%)]"
|
||||
"b" -> "bg-[linear-gradient(to_bottom,_black_33%,_white_67%)]"
|
||||
"c" -> "bg-[#{assigns.color}]"
|
||||
_ -> "bg-[linear-gradient(to_right,_black_33%,_white_67%)]"
|
||||
end
|
||||
|
||||
assigns =
|
||||
assign(
|
||||
assigns,
|
||||
label_too_long: String.length(assigns.label) > Constants.max_label_length(),
|
||||
preview_background: preview_background
|
||||
)
|
||||
|
||||
~H"""
|
||||
<div class="max-w-xl mx-auto p-4 space-y-6">
|
||||
@@ -41,10 +60,10 @@ defmodule LabelmakerWeb.Home do
|
||||
|
||||
<div
|
||||
class={
|
||||
"flex justify-center items-center p-4 overflow-hidden whitespace-nowrap bg-gradient-to-r from-black to-white border rounded transition duration-300 #{if label_too_long, do: "border-danger", else: "border-primary"} #{if label_too_long, do: "outline-danger", else: @outline != "none" && "outline-#{@outline}"}"}
|
||||
style={"height: calc(2rem + #{@preview_height}px); color: #{if label_too_long, do: "white", else: @color}; font-family: #{@font}; font-size: #{@size}px; line-height: #{@size}px;"}
|
||||
"flex justify-center items-center p-4 overflow-hidden whitespace-nowrap border rounded transition duration-300 #{@preview_background} #{if @label_too_long, do: "border-danger", else: "border-primary"} #{if @label_too_long, do: "outline-danger", else: @outline != "none" && "outline-#{@outline}"}"}
|
||||
style={"height: calc(2rem + #{@preview_height}px); color: #{if @label_too_long, do: "white", else: @color}; font-family: #{@font}; font-size: #{@size}px; line-height: #{@size}px; background-color: #{if @preview_bg == "c", do: @color, else: ""}"}
|
||||
>
|
||||
<%= if label_too_long do %>
|
||||
<%= if @label_too_long do %>
|
||||
{Constants.max_label_error()}
|
||||
<% else %>
|
||||
<%= for {str, i} <- Enum.with_index(@preview_text) do %>
|
||||
@@ -53,18 +72,54 @@ defmodule LabelmakerWeb.Home do
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex flex-row justify-between" style="margin-top: 5px;">
|
||||
<p class="text-xs text-gray-600 dark:text-gray-400 m-0 ml-1">
|
||||
Note: not all fonts and colors are available for preview.
|
||||
</p>
|
||||
<div class="flex flex-row gap-1">
|
||||
<div
|
||||
phx-click="update_preview"
|
||||
phx-value-bg="r"
|
||||
class="w-[12px] h-[12px] bg-gradient-to-r from-black to-white cursor-pointer"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
phx-click="update_preview"
|
||||
phx-value-bg="b"
|
||||
class="w-[12px] h-[12px] bg-gradient-to-b from-black to-white cursor-pointer"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
phx-click="update_preview"
|
||||
phx-value-bg="c"
|
||||
class="w-[12px] h-[12px] cursor-pointer"
|
||||
style={"background-color: #{@color}"}
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form phx-change="update_label" phx-submit="make_label" class="space-y-4">
|
||||
<form
|
||||
id="labelmaker"
|
||||
phx-hook="PersistData"
|
||||
phx-change="update_label"
|
||||
phx-submit="make_label"
|
||||
class="space-y-4"
|
||||
>
|
||||
<div>
|
||||
<label for="label" class="block text-sm font-medium">Label</label>
|
||||
<input
|
||||
phx-hook="EnterToNewline"
|
||||
type="text"
|
||||
id="label"
|
||||
name="label"
|
||||
value={@label}
|
||||
placeholder="Enter text"
|
||||
class={"mt-1 block w-full rounded border border-gray-300 px-3 py-2 text-fg-light dark:text-fg-dark dark:border-gray-600 focus:ring-primary dark:placeholder-gray-400/50 transition duration-300 #{if label_too_long, do: "bg-danger", else: "bg-secondary-light dark:bg-secondary-dark"}"}
|
||||
class={"mt-1 block w-full rounded border border-gray-300 px-3 py-2 text-fg-light dark:text-fg-dark dark:border-gray-600 focus:ring-primary dark:placeholder-gray-400/50 transition duration-300 #{if @label_too_long, do: "bg-danger", else: "bg-secondary-light dark:bg-secondary-dark"}"}
|
||||
/>
|
||||
<p class="text-xs text-gray-600 dark:text-gray-400 m-0 ml-1">
|
||||
<code>\n</code> or <Enter> for newlines
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
@@ -120,16 +175,15 @@ defmodule LabelmakerWeb.Home do
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="text-center">
|
||||
<button
|
||||
type="submit"
|
||||
class="inline-block bg-primary text-fg-light dark:text-fg-dark px-4 py-2 rounded hover:bg-highlight focus:ring-fg-light focus:dark:ring-fg-dark"
|
||||
>
|
||||
<a href={@link}>
|
||||
<button class="inline-block bg-primary text-fg-light dark:text-fg-dark px-4 py-2 rounded hover:bg-highlight focus:ring-fg-light focus:dark:ring-fg-dark">
|
||||
Create
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
defmodule LabelmakerWeb.Label do
|
||||
use LabelmakerWeb, :live_view
|
||||
alias LabelmakerWeb.Constants
|
||||
|
||||
@label_dir Path.join(:code.priv_dir(:labelmaker), "static/labels")
|
||||
File.mkdir_p!(@label_dir)
|
||||
|
||||
@defaults %{
|
||||
"label" => "Labelmaker",
|
||||
"font" => "Helvetica",
|
||||
"color" => "black",
|
||||
"size" => "24"
|
||||
}
|
||||
|
||||
@permitted_keys Map.keys(@defaults)
|
||||
|
||||
def mount(params, _session, socket) do
|
||||
options =
|
||||
@defaults
|
||||
|> Map.merge(params)
|
||||
|> Map.take(@permitted_keys)
|
||||
|
||||
filename =
|
||||
options
|
||||
|> inspect()
|
||||
|> (fn str -> :crypto.hash(:sha256, str) end).()
|
||||
|> Base.encode16(case: :lower)
|
||||
|
||||
filename = filename <> ".png"
|
||||
filepath = Path.join(@label_dir, filename)
|
||||
|
||||
unless File.exists?(filepath) do
|
||||
generate_image(options, filepath)
|
||||
end
|
||||
|
||||
{:ok,
|
||||
assign(socket,
|
||||
label: options["label"],
|
||||
image_path: ~p"/labels/#{filename}"
|
||||
)}
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
IO.inspect(Constants.color_count())
|
||||
IO.inspect(Constants.colors())
|
||||
|
||||
IO.inspect(Constants.font_count())
|
||||
IO.inspect(Constants.fonts())
|
||||
|
||||
~H"""
|
||||
<div>
|
||||
<h1>Label: {@label}</h1>
|
||||
<img src={@image_path} alt="" />
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp generate_image(options, filepath) do
|
||||
args = [
|
||||
"-background",
|
||||
"none",
|
||||
"-fill",
|
||||
options["color"],
|
||||
"-pointsize",
|
||||
options["size"],
|
||||
"-font",
|
||||
options["font"],
|
||||
"label:#{options["label"]}",
|
||||
filepath
|
||||
]
|
||||
|
||||
{_, 0} = System.cmd("magick", args)
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,16 @@
|
||||
defmodule LabelmakerWeb.Tools do
|
||||
# for the ~p sigil
|
||||
use Phoenix.VerifiedRoutes,
|
||||
endpoint: LabelmakerWeb.Endpoint,
|
||||
router: LabelmakerWeb.Router,
|
||||
statics: LabelmakerWeb.static_paths()
|
||||
|
||||
alias LabelmakerWeb.Constants
|
||||
|
||||
def process_parameters(parameters) do
|
||||
%{"label" => label, "size" => size} = parameters
|
||||
|
||||
link = ~p"/#{label}?#{Map.take(parameters, ["color", "font", "outline", "size"])}"
|
||||
line_breaks = Regex.scan(~r/#{Regex.escape("\\n")}/, label) |> length()
|
||||
size = String.to_integer(size)
|
||||
|
||||
@@ -16,6 +24,9 @@ defmodule LabelmakerWeb.Tools do
|
||||
do: {:label, String.slice(label, 0, Constants.max_label_length() + 1)},
|
||||
else: {:label, label}
|
||||
|
||||
{:link, _} ->
|
||||
{:link, link}
|
||||
|
||||
{:preview_height, _} ->
|
||||
{:preview_height, size + size * line_breaks}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 42 KiB |
Reference in New Issue
Block a user