summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-03 23:49:13 +0300
committerPaul Buetow <paul@buetow.org>2026-07-03 23:49:13 +0300
commit64ba6d89c2adbc8fbb5a94425641565a7eb373f8 (patch)
tree0a8323551e5105fd8f9954b094379c6601555940
parentb8faffb5e57f92654e801c44628ba12f1815d4a5 (diff)
ychat: make the chat UI mobile-friendly (task is0)
frameset.html used a classic HTML <frameset> (cols=*,150 / rows=*,0) to split the screen into message stream, userlist, and input areas. Framesets can't reflow via CSS media queries (cols/rows are fixed HTML attributes, not CSS) and are deprecated/unreliable in modern mobile browsers, making this the main mobile blocker. Replaced it with named iframes inside a flexbox layout (style.css: body.chatlayout and friends) — named iframes still expose the same window.<name> access the existing JS relies on (parent.stream.autoscroll()/stopscroll()), so no JS changes were needed. A media query restacks the userlist below the stream and grows the input row's height on narrow viewports instead of it eating ~40% of a phone's width as a fixed side column. Other mobile fixes: - Added <meta name="viewport"> to every template (was missing everywhere). - style.css: capped .text input width (size=60/40 attributes overflowed a ~375px screen; CSS width wins over the size attribute so one rule fixes every such field), set 16px input font-size to stop iOS Safari's auto-zoom-on-focus, gave submit/button inputs larger tap targets, and let wide tables (color picker, admin/help content) scroll horizontally instead of blowing out the page width. - input.html: replaced the two position:absolute control rows (fixed pixel offsets, no reflow) with wrapping flexbox rows (.input-row/.input-links) so the message box and action links stack on narrow screens. Verified by building the Dockerfile image, running it, registering/logging in a test user via curl, and confirming the *served* (token-substituted) HTML for index.html, register.html, frameset.html, and the stream/online/ input frames it references all contain the viewport meta tag and new CSS classes, with %%tmpid%% correctly substituted in iframe src URLs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
-rw-r--r--ychat/html/admin.html1
-rw-r--r--ychat/html/colors.html1
-rw-r--r--ychat/html/demo.html1
-rw-r--r--ychat/html/frameset.html27
-rw-r--r--ychat/html/help.html1
-rw-r--r--ychat/html/index.html1
-rw-r--r--ychat/html/input.html8
-rw-r--r--ychat/html/loggedin.html1
-rw-r--r--ychat/html/notfound.html1
-rw-r--r--ychat/html/online.html1
-rw-r--r--ychat/html/options.html1
-rw-r--r--ychat/html/register.html1
-rw-r--r--ychat/html/stream.html1
-rw-r--r--ychat/html/style.css111
14 files changed, 142 insertions, 15 deletions
diff --git a/ychat/html/admin.html b/ychat/html/admin.html
index 79152d8..7cfa487 100644
--- a/ychat/html/admin.html
+++ b/ychat/html/admin.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Admin options - %%ychat.version%%</title>
<link rel=stylesheet href="style.css" type=text/css />
</head>
diff --git a/ychat/html/colors.html b/ychat/html/colors.html
index cb3a9e2..8b142f9 100644
--- a/ychat/html/colors.html
+++ b/ychat/html/colors.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Color menu - %%ychat.version%%</title>
<link rel="stylesheet" href="style.css" type="text/css" />
<script lang="javascript" type="text/javascript">
diff --git a/ychat/html/demo.html b/ychat/html/demo.html
index c450ed8..04f8a4f 100644
--- a/ychat/html/demo.html
+++ b/ychat/html/demo.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%%ychat.version%%</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
diff --git a/ychat/html/frameset.html b/ychat/html/frameset.html
index 59ca44d..6df43da 100644
--- a/ychat/html/frameset.html
+++ b/ychat/html/frameset.html
@@ -2,19 +2,20 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%%ychat.version%%</title>
+ <link rel="stylesheet" href="style.css" type="text/css" />
</head>
- <frameset boders="0" rows="*,70">
- <noframes>
- Your browser does not support frames!
- </noframes>
- <frameset cols="*,150">
- <frame src="stream.html?event=stream&tmpid=%%tmpid%%" name="stream" />
- <frame src="online.html?event=online&tmpid=%%tmpid%%" name="online" />
- </frameset>
- <frameset rows="*,0">
- <frame src="input.html?event=input&tmpid=%%tmpid%%" name="input" />
- <frame src="blank.html" name="blank" />
- </frameset>
- </frameset>
+ <!-- See body.chatlayout in style.css for why this is iframes + flexbox
+ instead of a <frameset>: framesets can't reflow for mobile viewports. -->
+ <body class="chatlayout">
+ <div class="chatlayout-top">
+ <iframe class="stream-frame" src="stream.html?event=stream&tmpid=%%tmpid%%" name="stream">Your browser does not support iframes!</iframe>
+ <iframe class="online-frame" src="online.html?event=online&tmpid=%%tmpid%%" name="online">Your browser does not support iframes!</iframe>
+ </div>
+ <div class="chatlayout-bottom">
+ <iframe class="input-frame" src="input.html?event=input&tmpid=%%tmpid%%" name="input">Your browser does not support iframes!</iframe>
+ <iframe class="blank-frame" src="blank.html" name="blank"></iframe>
+ </div>
+ </body>
</html>
diff --git a/ychat/html/help.html b/ychat/html/help.html
index 243a7dc..cea8f80 100644
--- a/ychat/html/help.html
+++ b/ychat/html/help.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Chat-help - %%ychat.version%%</title>
<link rel="stylesheet" href="style.css" type=text/css />
</head>
diff --git a/ychat/html/index.html b/ychat/html/index.html
index 5f5e1bd..0a15e76 100644
--- a/ychat/html/index.html
+++ b/ychat/html/index.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%%ychat.version%%</title>
<link rel=stylesheet href="style.css" type="text/css" />
</head>
diff --git a/ychat/html/input.html b/ychat/html/input.html
index 9f56d5c..26ba8f6 100644
--- a/ychat/html/input.html
+++ b/ychat/html/input.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%%HTML_TITLE_TAG_CONTENT%%</title>
<link rel="stylesheet" href="style.css" type=text/css />
<script language="JavaScript">
@@ -36,12 +37,15 @@
</head>
<body>
<form method="GET" name="input" action="input.html" target="blank" onsubmit="return delout();">
- <div style="position: absolute; top: 5px;">
+ <!-- Was two position:absolute rows with fixed pixel offsets, which does
+ not reflow; a wrapping flex row (see .input-row/.input-links in
+ style.css) lets the controls stack on narrow screens instead. -->
+ <div class="input-row">
<input class="text" type="text" name="message" size="60" maxlength="%%chat.maxlength.message%%" />
<input type="submit" value="Send" accesskey='s' />
<input type="button" value="Select" accesskey='e' onclick="javascript:selectinput();" />
</div>
- <div style="position: absolute; top: 29px;">
+ <div class="input-links">
<a href='#' class="fancy" onclick="javascript:popup('colors.html?event=colors&tmpid=%%tmpid%%', 600, 480)">Colors</a>
<a href='#' class="fancy" onclick="javascript:popup('options.html?event=options&tmpid=%%tmpid%%', 600, 480)">Options</a>
<a href='#' class="fancy" onclick="javascript:popup('help.html?event=help&tmpid=%%tmpid%%', 600, 480)">Help</a>
diff --git a/ychat/html/loggedin.html b/ychat/html/loggedin.html
index 8e46439..620b6db 100644
--- a/ychat/html/loggedin.html
+++ b/ychat/html/loggedin.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Logged in users - %%ychat.version%%</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
diff --git a/ychat/html/notfound.html b/ychat/html/notfound.html
index 3dbdb17..444b06e 100644
--- a/ychat/html/notfound.html
+++ b/ychat/html/notfound.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel=stylesheet href="style.css" type="text/css" />
<title>%%HTML_TITLE_TAG_CONTENT%%</title>
</head>
diff --git a/ychat/html/online.html b/ychat/html/online.html
index 031724c..f674547 100644
--- a/ychat/html/online.html
+++ b/ychat/html/online.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel=stylesheet href="style.css" type="text/css" />
</head>
<body>
diff --git a/ychat/html/options.html b/ychat/html/options.html
index 26f0bdc..bc5c9be 100644
--- a/ychat/html/options.html
+++ b/ychat/html/options.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Options menu - %%ychat.version%%</title>
<link rel=stylesheet href="style.css" type="text/css" />
<body>
diff --git a/ychat/html/register.html b/ychat/html/register.html
index fb9e5d6..7c9f044 100644
--- a/ychat/html/register.html
+++ b/ychat/html/register.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nick registration - %%ychat.version%%</title>
<link rel=stylesheet href="style.css" type="text/css" />
</head>
diff --git a/ychat/html/stream.html b/ychat/html/stream.html
index 4855522..63e07fa 100644
--- a/ychat/html/stream.html
+++ b/ychat/html/stream.html
@@ -2,6 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>%%HTML_TITLE_TAG_CONTENT%%</title>
<link rel=stylesheet href="style.css" type="text/css" />
<script language="JavaScript">
diff --git a/ychat/html/style.css b/ychat/html/style.css
index 3c66631..cac1c8e 100644
--- a/ychat/html/style.css
+++ b/ychat/html/style.css
@@ -3,12 +3,55 @@ body {
font-family: arial, verdana;
background-color: #000000;
color: #FFFFFF;
+ margin: 0;
+ /* Breathing room on narrow viewports; the chat layout (body.chatlayout,
+ see below) needs the full viewport instead and overrides this back to 0. */
+ padding: 10px;
}
body.stream {
background-color: #333333;
}
+/* Text inputs used fixed "size" (character count) attributes sized for desktop
+ (e.g. size=60 for the chat message box), which overflow a ~375px phone
+ screen. CSS width wins over the size attribute, so capping it here fixes
+ every such input without having to edit each template. 16px font-size stops
+ iOS Safari from auto-zooming the page when a field is focused. */
+.text {
+ max-width: 100%;
+ box-sizing: border-box;
+ font-size: 16px;
+ padding: 4px;
+}
+
+input[type="submit"], input[type="button"] {
+ font-size: 16px;
+ padding: 8px 14px;
+ min-height: 40px;
+}
+
+/* Tables (e.g. the colors picker, admin/help content) were laid out for
+ desktop width and are not otherwise reflowed for mobile; let them scroll
+ horizontally instead of blowing out the page width. */
+@media (max-width: 480px) {
+ table {
+ display: block;
+ overflow-x: auto;
+ }
+}
+
+/* input.html's message box + link row, replacing the old absolute-positioned
+ divs (which had fixed pixel offsets and did not reflow) with a wrapping
+ flex row so controls stack instead of clipping on narrow screens. */
+.input-row, .input-links {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 6px;
+ padding: 4px 6px;
+}
+
h1, h2, h3 {
padding: 5px;
color: #000000;
@@ -42,3 +85,71 @@ a:hover {
color: #00FF00;
text-decoration: none;
}
+
+/* Layout for frameset.html. A classic HTML <frameset> cannot reflow for
+ narrow viewports (its cols/rows split is a fixed HTML attribute, not CSS,
+ so no media query can touch it) and framesets are deprecated/inconsistently
+ supported in modern mobile browsers. The same four panes (stream, online,
+ input, blank) are therefore built from named iframes inside a flexbox
+ layout, which behaves the same for the cross-frame JS (parent.stream.*)
+ since named iframes are exposed on window just like frameset frames, but
+ lets a media query restack the panes on small screens. */
+body.chatlayout {
+ margin: 0;
+ padding: 0;
+ height: 100vh;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+}
+
+.chatlayout-top {
+ flex: 1 1 auto;
+ min-height: 0;
+ display: flex;
+}
+
+.stream-frame {
+ flex: 1 1 auto;
+ border: 0;
+}
+
+.online-frame {
+ flex: 0 0 150px;
+ border: 0;
+ border-left: 1px solid #555555;
+}
+
+.chatlayout-bottom {
+ flex: 0 0 70px;
+ display: flex;
+}
+
+.input-frame {
+ flex: 1 1 auto;
+ border: 0;
+}
+
+/* Sink frame for form targets, kept out of the layout instead of the former
+ 0-height frame row; navigating a hidden named iframe still works. */
+.blank-frame {
+ display: none;
+}
+
+@media (max-width: 600px) {
+ /* Userlist moves below the message stream as a short horizontal strip
+ instead of eating ~40% of a phone's width as a 150px side column. */
+ .chatlayout-top {
+ flex-direction: column;
+ }
+ .online-frame {
+ flex: 0 0 90px;
+ border-left: 0;
+ border-top: 1px solid #555555;
+ }
+ /* Input controls wrap onto two lines on narrow screens (see input.html),
+ so the input frame needs more height than the desktop 70px. */
+ .chatlayout-bottom {
+ flex: 0 0 108px;
+ }
+}