App-news
view release on metacpan or search on metacpan
script/news view on Meta::CPAN
%= text_field 'subject', required => undef
<p>
%= label_for body => 'Article'
%= text_area 'body', required => undef
<p>
%= check_box wrap => 1, checked => 1, id => 'wrap'
%= label_for wrap => 'Wrap'
%= submit_button 'Post', id => 'post'
% end
@@ posted.html.ep
% layout 'default';
% title 'Posted';
% if ($ok) {
<h1>Posted!</h1>
<p>The article was posted to <%= link_to url_for('group', group => $group) => begin %><%= $group %><% end %>.
% } else {
<h1>Error</h1>
<p>Oops. Looks like posting to <%= link_to url_for('group', group => $group) => begin %><%= $group %><% end %> failed!
% }
@@ latest.html.ep
% layout "default";
% title "New news";
<h1>New news</h1>
<p><%= link_to url_for('index') => begin %>List all groups<% end %>
% if (@$list) {
<table>
<tr><th class="date">Date</th><th class="from">From</th><th class="subject">Subject</th></tr>
% my $date = "";
% for my $article (@$list) {
% if ($article->{date}->[0] ne $date) {
% $date = $article->{date}->[0];
<tr><td class="day"><%= $date %></td><td></td><td></td></tr>
% }
% if ($article->{tag}) {
% my $re = quotemeta($article->{tag});
% my @part = split(/$re/, $article->{subject}, 2);
<tr><td class="time"><a href="<%= $article->{url} %>"><%= $article->{date}->[1] %></a></td><td class="from"><%= $article->{from} %></td><td class="subject"><%= $part[0] %><%= link_to url_for('tag', group => $article->{group}, tag => $article->{tag}) ...
% } else {
<tr><td class="time"><a href="<%= $article->{url} %>"><%= $article->{date}->[1] %></a></td><td class="from"><%= $article->{from} %></td><td class="subject"><%= $article->{subject} %></td></tr>
% }
% }
</table>
% } else {
<p>No news is good news.
<p>Uhh⦠ð¤
% }
@@ layouts/default.html.ep
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
%= stylesheet begin
body {
color: #111;
background-color: #fffff8;
padding: 1ch;
max-width: 80ch;
font-size: 12pt;
font-family: Lucida Console,Lucida Sans Typewriter,monaco,DejaVu Mono,Bitstream Vera Sans Mono,monospace;
hyphens: auto;
}
@media (prefers-color-scheme: dark) {
body {
color: #7f7;
background-color: #010;
}
a:link { color: #99f; }
a:visited { color: #86f; }
a:hover { color: #eef; }
}
.day { padding-top: 1ch; }
.time, .status { text-align: center; }
td { min-width: 10ch; padding: 0 0.5ch; }
label { display: inline-block; min-width: 10ch; }
label[for=wrap] { display: inline; }
input[type=password], input[type=text] { width: 30ch; }
textarea { width: 100%; height: 20ch; }
.button { display: inline-block; }
pre { white-space: pre-wrap; }
blockquote { border-left: 0.5ch solid gray; padding-left: 0.5ch; margin: 0; margin-top: 0.5ch; }
% end
<meta name="viewport" content="width=device-width">
</head>
<body lang="en">
<%= content %>
<hr>
<p>
<a href="https://campaignwiki.org/news">News</a> 
<a href="https://alexschroeder.ch/cgit/news/about/">Source</a> 
<a href="https://alexschroeder.ch/wiki/Contact">Alex Schroeder</a>
</body>
</html>
( run in 1.560 second using v1.01-cache-2.11-cpan-ceb78f64989 )