73 lines
2.4 KiB
Java
73 lines
2.4 KiB
Java
|
|
package org.openautonomousconnection.webserver.utils;
|
||
|
|
|
||
|
|
import java.nio.charset.StandardCharsets;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Small HTML helpers for server-side rendering.
|
||
|
|
*/
|
||
|
|
public final class Html {
|
||
|
|
|
||
|
|
private Html() {}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Escapes text for HTML.
|
||
|
|
*
|
||
|
|
* @param s input
|
||
|
|
* @return escaped
|
||
|
|
*/
|
||
|
|
public static String esc(String s) {
|
||
|
|
if (s == null) return "";
|
||
|
|
return s.replace("&", "&")
|
||
|
|
.replace("<", "<")
|
||
|
|
.replace(">", ">")
|
||
|
|
.replace("\"", """);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Encodes to UTF-8 bytes.
|
||
|
|
*
|
||
|
|
* @param html html
|
||
|
|
* @return bytes
|
||
|
|
*/
|
||
|
|
public static byte[] utf8(String html) {
|
||
|
|
return (html == null ? "" : html).getBytes(StandardCharsets.UTF_8);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Simple page wrapper.
|
||
|
|
*
|
||
|
|
* @param title title
|
||
|
|
* @param body body html
|
||
|
|
* @return full html
|
||
|
|
*/
|
||
|
|
public static String page(String title, String body) {
|
||
|
|
return """
|
||
|
|
<!doctype html>
|
||
|
|
<html>
|
||
|
|
<head>
|
||
|
|
<meta charset="utf-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
|
<title>%s</title>
|
||
|
|
<style>
|
||
|
|
body{font-family:system-ui,Segoe UI,Arial,sans-serif;background:#0f111a;color:#e5e7eb;margin:0;padding:24px;}
|
||
|
|
a{color:#60a5fa;text-decoration:none} a:hover{text-decoration:underline}
|
||
|
|
.card{background:#111827;border:1px solid #1f2937;border-radius:12px;padding:16px;max-width:900px}
|
||
|
|
input,select{background:#0b1220;color:#e5e7eb;border:1px solid #243042;border-radius:8px;padding:10px;width:100%%;box-sizing:border-box}
|
||
|
|
button{background:#2563eb;color:white;border:none;border-radius:8px;padding:10px 14px;cursor:pointer}
|
||
|
|
button:hover{filter:brightness(1.05)}
|
||
|
|
.row{display:flex;gap:12px;flex-wrap:wrap}
|
||
|
|
.col{flex:1;min-width:220px}
|
||
|
|
.muted{color:#94a3b8}
|
||
|
|
.err{color:#fca5a5}
|
||
|
|
.ok{color:#86efac}
|
||
|
|
code{background:#0b1220;padding:2px 6px;border-radius:6px}
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
%s
|
||
|
|
</body>
|
||
|
|
</html>
|
||
|
|
""".formatted(esc(title), body == null ? "" : body);
|
||
|
|
}
|
||
|
|
}
|