diff options
author | Yorhel <git@yorhel.nl> | 2019-09-17 20:26:09 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2019-09-17 20:28:55 +0200 |
commit | cc2a1d72e499f7befe1b615a1322952dfb628fab (patch) | |
tree | 19ebe2931d082453d7004894da8259014ce23ca4 /lib/VNWeb/HTML.pm | |
parent | b34b37ba5acdf423ab30f4927cbdbbc704e91590 (diff) |
v2rw: Initial start on an incremental rewrite; Layout HTML first
I copied and modified VN3::DB to VNWeb::DB, but it isn't used yet. Now
that I think about it, that module isn't "web" specific at all and
should perhaps be in the VNDB:: namespace. Oh well.
Diffstat (limited to 'lib/VNWeb/HTML.pm')
-rw-r--r-- | lib/VNWeb/HTML.pm | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/lib/VNWeb/HTML.pm b/lib/VNWeb/HTML.pm new file mode 100644 index 00000000..e32af3a9 --- /dev/null +++ b/lib/VNWeb/HTML.pm @@ -0,0 +1,200 @@ +package VNWeb::HTML; + +use v5.24; +use warnings; +use TUWF ':html5_', 'uri_escape'; +use Exporter 'import'; +use JSON::XS; + +our @EXPORT = qw/ + clearfloat_ + debug_ + framework_ +/; + + +# Ugly hack to move rendering down below the float object. +sub clearfloat_ { div_ class => 'clearfloat', '' } + + +# Throw any data structure on the page for inspection. +sub debug_ { + return if !tuwf->debug; + # This provides a nice JSON browser in FF, not sure how other browsers render it. + my $data = uri_escape(JSON::XS->new->canonical->encode($_[0])); + a_ style => 'margin: 0 5px', title => 'Debug', href => 'data:application/json,'.$data, ' ⚙ '; +} + + +sub _head_ { + my $o = shift; + my $skin = tuwf->reqGet('skin') || tuwf->authPref('skin') || tuwf->{skin_default}; + $skin = tuwf->{skin_default} if !tuwf->{skins}{$skin}; + + title_ $o->{title}.' | vndb'; + link_ rel => 'shortcut icon', href => '/favicon.ico', type => 'image/x-icon'; + link_ rel => 'stylesheet', href => tuwf->{url_static}.'/s/'.$skin.'/style.css?'.tuwf->{version}, type => 'text/css', media => 'all'; + link_ rel => 'search', type => 'application/opensearchdescription+xml', title => 'VNDB VN Search', href => tuwf->reqBaseURI().'/opensearch.xml'; + style_ type => 'text/css', tuwf->authPref('customcss') =~ s/\n/ /rg if tuwf->authPref('customcss'); + if($o->{feeds}) { + link_ rel => 'alternate', type => 'application/atom+xml', href => "/feeds/announcements.atom", title => 'Site Announcements'; + link_ rel => 'alternate', type => 'application/atom+xml', href => "/feeds/changes.atom", title => 'Recent Changes'; + link_ rel => 'alternate', type => 'application/atom+xml', href => "/feeds/posts.atom", title => 'Recent Posts'; + } + meta_ name => 'robots', content => 'noindex, follow' if $o->{noindex}; + + # Opengraph metadata + if($o->{og}) { + $o->{og}{site_name} ||= 'The Visual Novel Database'; + $o->{og}{type} ||= 'object'; + $o->{og}{image} ||= 'https://s.vndb.org/s/angel/bg.jpg'; # TODO: Something better + $o->{og}{url} ||= tuwf->reqURI; + $o->{og}{title} ||= $o->{title}; + meta_ property => "og:$_", content => ($o->{og}{$_} =~ s/\n/ /gr) for sort keys $o->{og}->%*; + } +} + + +sub _menu_ { + my $o = shift; + div_ class => 'menubox', sub { + h2_ 'Menu'; + div_ sub { + a_ href => '/', 'Home'; br_; + a_ href => '/v/all', 'Visual novels'; br_; + b_ class => 'grayedout', '> '; a_ href => '/g', 'Tags'; br_; + a_ href => '/r', 'Releases'; br_; + a_ href => '/p/all', 'Producers'; br_; + a_ href => '/s/all', 'Staff'; br_; + a_ href => '/c/all', 'Characters'; br_; + b_ class => 'grayedout', '> '; a_ href => '/i', 'Traits'; br_; + a_ href => '/u/all', 'Users'; br_; + a_ href => '/hist', 'Recent changes'; br_; + a_ href => '/t', 'Discussion board'; br_; + a_ href => '/d6', 'FAQ'; br_; + a_ href => '/v/rand','Random visual novel'; + }; + form_ action => '/v/all', method => 'get', id => 'search', sub { + fieldset_ sub { + legend_ 'Search'; + input_ type => 'text', class => 'text', id => 'sq', name => 'sq', value => $o->{search}||'', placeholder => 'search'; + input_ type => 'submit', class => 'submit', value => 'Search'; + } + } + }; + + div_ class => 'menubox', sub { + my $uid = sprintf '/u%d', tuwf->authInfo->{id}; + my $nc = tuwf->authInfo->{notifycount}; + h2_ sub { a_ href => $uid, ucfirst tuwf->authInfo->{username} }; + div_ sub { + a_ href => "$uid/edit", 'My Profile'; br_; + a_ href => "$uid/list", 'My Visual Novel List'; br_; + a_ href => "$uid/votes",'My Votes'; br_; + a_ href => "$uid/wish", 'My Wishlist'; br_; + a_ href => "$uid/notifies", $nc ? (class => 'notifyget') : (), 'My Notifications'.($nc?" ($nc)":''); br_; + a_ href => "$uid/hist", 'My Recent Changes'; br_; + a_ href => '/g/links?u='.tuwf->authInfo->{id}, 'My Tags'; br_; + br_; + if(tuwf->authCan('edit')) { + a_ href => '/v/add', 'Add Visual Novel'; br_; + a_ href => '/p/add', 'Add Producer'; br_; + a_ href => '/s/new', 'Add Staff'; br_; + a_ href => '/c/new', 'Add Character'; br_; + } + br_; + a_ href => "$uid/logout", 'Logout'; + } + } if tuwf->authInfo->{id}; + + div_ class => 'menubox', sub { + h2_ 'User menu'; + div_ sub { + my $ref = uri_escape tuwf->reqPath().tuwf->reqQuery(); + a_ href => "/u/login?ref=$ref", 'Login'; br_; + a_ href => '/u/newpass', 'Password reset'; br_; + a_ href => '/u/register', 'Register'; br_; + } + } if !tuwf->authInfo->{id}; + + div_ class => 'menubox', sub { + h2_ 'Database Statistics'; + div_ sub { + dl_ sub { + dt_ 'Visual Novels'; dd_ tuwf->{stats}{vn}; + dt_ sub { b_ class => 'grayedout', '> '; lit_ 'Tags' }; + dd_ tuwf->{stats}{tags}; + dt_ 'Releases'; dd_ tuwf->{stats}{releases}; + dt_ 'Producers'; dd_ tuwf->{stats}{producers}; + dt_ 'Staff'; dd_ tuwf->{stats}{staff}; + dt_ 'Characters'; dd_ tuwf->{stats}{chars}; + dt_ sub { b_ class => 'grayedout', '> '; lit_ 'Traits' }; + dd_ tuwf->{stats}{traits}; + }; + clearfloat_; + } + }; +} + + +sub _footer_ { + my $q = tuwf->dbRow('SELECT vid, quote FROM quotes ORDER BY RANDOM() LIMIT 1'); + if($q && $q->{vid}) { + lit_ '"'; + a_ href => "/v$q->{vid}", style => 'text-decoration: none', $q->{quote}; + txt_ '"'; + br_; + } + txt_ sprintf 'vndb %s | ', tuwf->{version}; + a_ href => '/d7', 'about us'; + lit_ ' | '; + a_ href => 'irc://irc.synirc.net/vndb', '#vndb'; + lit_ ' | '; + a_ href => sprintf('mailto:%s', tuwf->{admin_email}), tuwf->{admin_email}; + lit_ ' | '; + a_ href => tuwf->{source_url}, 'source'; + + if(tuwf->debug) { + lit_ ' | '; + tuwf->dbCommit; # Hack to measure the commit time + + my $sql = uri_escape join "\n", map { + my($sql, $params, $time) = @$_; + sprintf " [%6.2fms] %s | %s", $time*1000, $sql, + join ', ', map "$_:".DBI::neat($params->{$_}), + sort { $a =~ /^[0-9]+$/ && $b =~ /^[0-9]+$/ ? $a <=> $b : $a cmp $b } + keys %$params; + } tuwf->{_TUWF}{DB}{queries}->@*; + a_ href => 'data:text/plain,'.$sql, 'SQL'; + lit_ ' | '; + + my $modules = uri_escape join "\n", sort keys %INC; + a_ href => 'data:text/plain,'.$modules, 'Modules'; + } +} + + +# Options: +# title => $title +# noindex => 1/0 +# feeds => 1/0 +# search => $query +# og => { opengraph metadata } +# sub { content } +sub framework_ { + my $cont = pop; + my %o = @_; + + html_ lang => 'en', sub { + head_ sub { _head_ \%o }; + body_ sub { + div_ id => 'bgright', ' '; + div_ id => 'header', sub { h1_ sub { a_ href => '/', 'the visual novel database' } }; + div_ id => 'menulist', sub { _menu_ \%o }; + div_ id => 'maincontent', $cont; + div_ id => 'footer', sub { _footer_ }; + }; + } +} + +1; |