diff options
author | Yorhel <git@yorhel.nl> | 2020-10-31 09:29:01 +0100 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2020-10-31 09:59:17 +0100 |
commit | 90e2dc96e786da59722b3a94dc74c2325776231d (patch) | |
tree | c68cb66bd2412110a548ef17e0a8cb1c2afce843 | |
parent | fea1149af17b784aed285d71c39b2ba2690d1cfe (diff) |
Advsearch: Display results
Same browse UI as the old one. I hope to extend this UI with a lot more
options, later on. But let's first focus on feature parity.
-rw-r--r-- | elm/AdvSearch/Main.elm | 3 | ||||
-rw-r--r-- | lib/VNWeb/VN/List.pm | 73 |
2 files changed, 72 insertions, 4 deletions
diff --git a/elm/AdvSearch/Main.elm b/elm/AdvSearch/Main.elm index 56352b6d..a86438fb 100644 --- a/elm/AdvSearch/Main.elm +++ b/elm/AdvSearch/Main.elm @@ -101,7 +101,4 @@ view model = div [ class "advsearch" ] --, input [ type_ "button", class "submit", value "Advanced mode" ] [] -- TODO: Advanced mode where you can construct arbitrary queries. [ input [ type_ "submit", class "submit", value "Search" ] [] ] - , pre [] - [ text <| Maybe.withDefault "" <| Maybe.map (\v -> JE.encode 2 (encodeQuery v)) (fqueryToQuery model.query) - ] ] diff --git a/lib/VNWeb/VN/List.pm b/lib/VNWeb/VN/List.pm index a9cf6fb4..e968db55 100644 --- a/lib/VNWeb/VN/List.pm +++ b/lib/VNWeb/VN/List.pm @@ -4,11 +4,54 @@ use VNWeb::Prelude; use VNWeb::AdvSearch; +sub listing_ { + my($opt, $list, $count) = @_; + + # TODO: query_encode() should recognize and encode the search query automatically. + $opt->{f} = JSON::XS->new->encode($opt->{f}) if $opt->{f}; + my sub url { '?'.query_encode %$opt, @_ } + + paginate_ \&url, $opt->{p}, [$count, 50], 't'; + div_ class => 'mainbox browse vnbrowse', sub { + table_ class => 'stripe', sub { + thead_ sub { tr_ sub { + td_ class => 'tc1', sub { txt_ 'Title'; sortable_ 'title', $opt, \&url }; + td_ class => 'tc7', ''; + td_ class => 'tc2', ''; + td_ class => 'tc3', ''; + td_ class => 'tc4', sub { txt_ 'Released'; sortable_ 'rel', $opt, \&url }; + td_ class => 'tc5', sub { txt_ 'Popularity'; sortable_ 'pop', $opt, \&url }; + td_ class => 'tc6', sub { txt_ 'Rating'; sortable_ 'rating', $opt, \&url }; + } }; + tr_ sub { + td_ class => 'tc1', sub { a_ href => "/v$_->{id}", title => $_->{original}||$_->{title}, $_->{title} }; + td_ class => 'tc7', sub { + b_ class => $_->{userlist_obtained} == $_->{userlist_all} ? 'done' : 'todo', sprintf '%d/%d', $_->{userlist_obtained}, $_->{userlist_all} if $_->{userlist_all}; + abbr_ title => join(', ', $_->{vnlist_labels}->@*), scalar $_->{vnlist_labels}->@* if $_->{vnlist_labels} && $_->{vnlist_labels}->@*; + abbr_ title => 'No labels', ' ' if $_->{vnlist_labels} && !$_->{vnlist_labels}->@*; + }; + td_ class => 'tc2', sub { join_ '', sub { abbr_ class => "icons $_", title => $PLATFORM{$_}, '' if $_ ne 'unk' }, sort $_->{platforms}->@* }; + td_ class => 'tc3', sub { join_ '', sub { abbr_ class => "icons lang $_", title => $LANGUAGE{$_}, '' }, reverse sort $_->{lang}->@* }; + td_ class => 'tc4', sub { rdate_ $_->{c_released} }; + td_ class => 'tc5', sprintf '%.2f', ($_->{c_popularity}||0)*100; + td_ class => 'tc6', sub { + txt_ sprintf '%.2f', ($_->{c_rating}||0)/10; + b_ class => 'grayedout', sprintf ' (%d)', $_->{c_votecount}; + }; + } for @$list; + } + }; + paginate_ \&url, $opt->{p}, [$count, 50], 'b'; +} + + TUWF::get qr{/experimental/v}, sub { my $opt = tuwf->validate(get => q => { onerror => '' }, p => { upage => 1 }, f => { advsearch => 'v' }, + s => { onerror => 'title', enum => [qw/title rel pop rating/] }, + o => { onerror => 'a', enum => ['a','d'] }, )->data; my $where = sql_and @@ -18,6 +61,33 @@ TUWF::get qr{/experimental/v}, sub { my $time = time; my $count = tuwf->dbVali('SELECT count(*) FROM vn v WHERE', $where); + my $list = $count && tuwf->dbPagei({results => 50, page => $opt->{p}}, ' + SELECT v.id, v.title, v.original, v.c_released, v.c_popularity, v.c_votecount, v.c_rating, v.c_platforms::text[] AS platforms, v.c_languages::text[] AS lang + , vl.userlist_all, vl.userlist_obtained + FROM vn v + LEFT JOIN ( + SELECT irv.vid, COUNT(*) AS userlist_all + , SUM(CASE WHEN irl.status = 1+1 THEN 1 ELSE 0 END) AS userlist_obtained + FROM rlists irl + JOIN releases_vn irv ON irv.id = irl.rid + WHERE irl.uid =', \auth->uid, ' + GROUP BY irv.vid + ) AS vl ON vl.vid = v.id + WHERE', $where, ' + ORDER BY', sprintf { + title => 'v.title %s', + rel => 'v.c_released %s, v.title', + pop => 'v.c_popularity %s NULLS LAST, v.title', + rating => 'v.c_rating %s NULLS LAST, v.title' + }->{$opt->{s}}, $opt->{o} eq 'a' ? 'ASC' : 'DESC' + ); + enrich_flatten vnlist_labels => id => vid => sub { sql ' + SELECT uvl.vid, ul.label + FROM ulist_vns_labels uvl + JOIN ulist_labels ul ON ul.uid = uvl.uid AND ul.id = uvl.lbl + WHERE uvl.uid =', \auth->uid, 'AND uvl.vid IN', $_[0], ' + ORDER BY CASE WHEN ul.id < 10 THEN ul.id ELSE 10 END, ul.label' + }, $list if $count && auth; $time = time - $time; framework_ title => 'Browse visual novels', sub { @@ -32,8 +102,9 @@ TUWF::get qr{/experimental/v}, sub { searchbox_ v => $opt->{q}; as_elm_ v => $opt->{f}; }; - p_ sprintf '%d results in %.3fs', $count, $time; + p_ class => 'center', sprintf '%d results in %.3fs', $count, $time; }; + listing_ $opt, $list, $count if $count; }; }; |