Browse Source

Improve search index & result layout.

scossu 1 week ago
parent
commit
171a4a6442

+ 36 - 13
src/generator.lua

@@ -32,9 +32,9 @@ local ICON_EXT = ".svg"
 local asset_dir = pkar.config.htmlgen.out_dir
 local asset_dir = pkar.config.htmlgen.out_dir
 local index_path = path.join(asset_dir, "js", "fuse_index.json")
 local index_path = path.join(asset_dir, "js", "fuse_index.json")
 local keys_path = path.join(asset_dir, "js", "fuse_keys.json")
 local keys_path = path.join(asset_dir, "js", "fuse_keys.json")
-local idx_ignore = {first = true, next = true,}
+local idx_ignore = {first = true, next = true}
 -- Collector for all search term keys.
 -- Collector for all search term keys.
-local idx_keys = {}
+local idx_keys
 
 
 -- HTML templates. Compile them only once.
 -- HTML templates. Compile them only once.
 -- TODO Add override for user-maintained templates.
 -- TODO Add override for user-maintained templates.
@@ -347,28 +347,43 @@ local function generate_ores(s, mconf)
 end
 end
 
 
 
 
-M.generate_res_idx = function(s, mconf)
+M.generate_search_idx = function(s, mconf)
     local rrep = {
     local rrep = {
-        id = nsm.denormalize_uri(s.data),
+        id = s.data:gsub("^.*/", ""),
         tn = get_tn_url(s),
         tn = get_tn_url(s),
         href = pkar.gen_pairtree("/res", s.data, ".html", true),
         href = pkar.gen_pairtree("/res", s.data, ".html", true),
+        content_type = mconf.id,
+        type = mconf.lineage,
+        icon = get_icon_url(mconf.lineage),
     }
     }
 
 
-    local attrs = repo.gr:connections(s, term.LINK_OUTBOUND)
-
     local function format_value(pname, o)
     local function format_value(pname, o)
         logger:debug("Adding value to " .. pname .. ": " .. ((o or NT).data or "nil"))
         logger:debug("Adding value to " .. pname .. ": " .. ((o or NT).data or "nil"))
         local v
         local v
         if pname == "type" or pname == "content_type" then
         if pname == "type" or pname == "content_type" then
-            v = nsm.denormalize_uri(o.data)
+            v = model.uri_to_id[p]
         else v = o.data
         else v = o.data
         end
         end
         return v
         return v
     end
     end
 
 
+    local attrs = repo.gr:connections(s, term.LINK_OUTBOUND)
+    local fpath
+
     for p, ots in pairs(attrs) do
     for p, ots in pairs(attrs) do
-        local pname = nsm.denormalize_uri(p.data)
+        local pname
+        if p == pkar.CONTENT_TYPE_P then goto skip end
+        if p == pkar.PATH_P then
+            if mconf.types.file then
+                _, fpath = next(ots)
+                rrep.fname = path.basename(fpath.data)
+            end
+            goto skip
+        end
+        pname = model.uri_to_id[nsm.denormalize_uri(p.data)]
+        if not pname then goto skip end
         local pconf = (mconf.properties or NT)[pname] or NT
         local pconf = (mconf.properties or NT)[pname] or NT
+        -- TODO dereference & index resource values.
         if idx_ignore[pname] or pconf.type == "resource" then goto skip end
         if idx_ignore[pname] or pconf.type == "resource" then goto skip end
 
 
         local attr
         local attr
@@ -384,7 +399,7 @@ M.generate_res_idx = function(s, mconf)
             attr = format_value(pname, o)
             attr = format_value(pname, o)
         end
         end
 
 
-        rrep[pconf.label or pname] = attr  -- Add to search index.
+        rrep[pname] = attr  -- Add to search index.
         idx_keys[pname] = true  -- Add to search keys.
         idx_keys[pname] = true  -- Add to search keys.
         ::skip::
         ::skip::
     end
     end
@@ -434,7 +449,7 @@ M.generate_resource = function(s)
     else assert(generate_dres(s, mconf)) end
     else assert(generate_dres(s, mconf)) end
 
 
     -- Generate JSON rep and append to search index.
     -- Generate JSON rep and append to search index.
-    idx_rep = M.generate_res_idx(s, mconf)
+    idx_rep = M.generate_search_idx(s, mconf)
     json_rep = "  " .. json.encode(idx_rep)
     json_rep = "  " .. json.encode(idx_rep)
     ofh = assert(io.open(index_path, "a"))
     ofh = assert(io.open(index_path, "a"))
     ofh:write(json_rep)
     ofh:write(json_rep)
@@ -460,7 +475,7 @@ M.generate_resources = function()
     -- Close the open list brace in the JSON template after all the resources
     -- Close the open list brace in the JSON template after all the resources
     -- have been added.
     -- have been added.
     ofh = assert(io.open(index_path, "a"))
     ofh = assert(io.open(index_path, "a"))
-    ofh:write("{}]")  -- Add empty object to validate the last comma
+    ofh:write("  {}\n]")  -- Add empty object to validate the last comma
     ofh:close()
     ofh:close()
 
 
     -- Write index keys.
     -- Write index keys.
@@ -474,7 +489,7 @@ M.generate_resources = function()
 end
 end
 
 
 
 
-M.generate_idx = function()
+M.generate_homepage = function()
     local idx_data = {objects = {}, collections = {}}
     local idx_data = {objects = {}, collections = {}}
     -- Get all subject of type: Artifact.
     -- Get all subject of type: Artifact.
     local s_ts = repo.gr:term_set(
     local s_ts = repo.gr:term_set(
@@ -558,11 +573,19 @@ M.generate_site = function()
     -- Copy static assets.
     -- Copy static assets.
     dir.clonetree("templates/assets", M.asset_dir, dir.copyfile)
     dir.clonetree("templates/assets", M.asset_dir, dir.copyfile)
 
 
+    -- Clear local search index keys.
+    idx_keys = {
+        id = true,
+        content_type = true,
+        type = true,
+        fname = true,
+    }
+
     -- Generate individual resource pages, RDF, and JSON index.
     -- Generate individual resource pages, RDF, and JSON index.
     assert(M.generate_resources())
     assert(M.generate_resources())
 
 
     -- Generate index page.
     -- Generate index page.
-    assert(M.generate_idx())
+    assert(M.generate_homepage())
 end
 end
 
 
 
 

+ 46 - 1
templates/assets/css/pkar.css

@@ -1,3 +1,15 @@
+main { overflow: hidden; }
+
+section {
+    max-width: 120rem;
+    margin: 0 auto;
+    padding: 2rem;
+}
+
+.title {
+    text-align: center;
+}
+
 /* Hidden only on visual browsers. */
 /* Hidden only on visual browsers. */
 .v_hidden {
 .v_hidden {
     position:absolute;
     position:absolute;
@@ -21,5 +33,38 @@
 
 
 .title_icon {
 .title_icon {
     width: 3rem;
     width: 3rem;
-    margin: 0.5rem;
+    margin: 0 .6rem 0 0;
+    vertical-align: middle;
+}
+
+.body_icon {
+    width: 2.5rem;
+    margin: 0 .4rem 0 0;
+    vertical-align: middle;
+}
+
+.slideshow li {
+    list-style-type: none;
+    display: block;
+    margin: .4rem auto;
+    text-align: center;
+}
+
+.slideshow a {
+    display: inline-block;
+    text-align: left;
+}
+
+#result_list li {
+    list-style-type: none;
+    display: block;
+    margin: 2rem auto;
+}
+
+#result_list li p {
+    margin-bottom: 1rem;
+}
+
+.result_tn {
+    margin-right: 1.5rem;
 }
 }

+ 33 - 5
templates/assets/js/search.js

@@ -23,18 +23,46 @@ if (qstring != undefined) {
 
 
             const res_tn = document.createElement("img");
             const res_tn = document.createElement("img");
             res_tn.setAttribute("src", window.webroot + rsrc.tn);
             res_tn.setAttribute("src", window.webroot + rsrc.tn);
-            res_tn.setAttribute("alt", rsrc.Title);
+            res_tn.setAttribute("alt", rsrc.label);
+            res_tn.classList.add("result_tn");
+            res_tn.classList.add("float-left");
 
 
-            res_txt = document.createTextNode(rsrc.Title);
+            const res_icon = document.createElement("img");
+            res_icon.setAttribute("src", rsrc.icon);
+            res_icon.setAttribute("alt", rsrc.content_type);
+            res_icon.classList.add("body_icon");
+
+            const res_title_txt = document.createTextNode(rsrc.label || rsrc.fname);
 
 
             const res_link = document.createElement("a");
             const res_link = document.createElement("a");
             res_link.setAttribute("href", window.webroot + rsrc.href);
             res_link.setAttribute("href", window.webroot + rsrc.href);
-            res_link.appendChild(res_tn);
-            res_link.appendChild(res_txt);
+            res_link.appendChild(res_icon);
+            res_link.appendChild(res_title_txt);
+
+            const res_title = document.createElement("h4");
+            res_title.appendChild(res_link);
+
+            const res_id_txt = document.createTextNode("ID: " + rsrc.id);
+            res_id = document.createElement("p");
+            res_id.appendChild(res_id_txt);
+
+            const res_date_txt = document.createTextNode("Submitted: " + rsrc.submitted);
+            res_date = document.createElement("p");
+            res_date.appendChild(res_date_txt);
+
+            const res_box = document.createElement("div");
+            res_box.classList.add("column");
+            res_box.classList.add("search_item");
+            res_box.appendChild(res_title);
+            res_box.appendChild(res_id);
+            res_box.appendChild(res_date);
 
 
             const res_li = document.createElement("li");
             const res_li = document.createElement("li");
             res_li.setAttribute("id", "sres-" + rsrc.id);
             res_li.setAttribute("id", "sres-" + rsrc.id);
-            res_li.appendChild(res_link);
+            res_li.classList.add("row");
+            res_li.classList.add("clearfix");
+            res_li.appendChild(res_tn);
+            res_li.appendChild(res_box);
 
 
             res_el.appendChild(res_li);
             res_el.appendChild(res_li);
         });
         });

+ 7 - 5
templates/index.html

@@ -12,7 +12,7 @@
     <body>
     <body>
         <%- header_tpl({site_title = site_title}) %>
         <%- header_tpl({site_title = site_title}) %>
         <main>
         <main>
-            <h1><%= title %></h1>
+            <h1 class="title"><%= title %></h1>
             <section id="search">
             <section id="search">
                 <h2>Search</h2>
                 <h2>Search</h2>
                 <form action="/" method="GET">
                 <form action="/" method="GET">
@@ -34,12 +34,13 @@
             </section>
             </section>
             <section id="coll_list">
             <section id="coll_list">
                 <h2>Recent collections</h2>
                 <h2>Recent collections</h2>
-                <ul>
+                <ul class="row slideshow">
                 <% for _, coll in ipairs(idx_data.collections) do %>
                 <% for _, coll in ipairs(idx_data.collections) do %>
-                    <li class="coll_link">
+                    <li class="column coll_link">
                         <a href="<%= coll.href %>">
                         <a href="<%= coll.href %>">
                             <%if coll.tn then %>
                             <%if coll.tn then %>
                                 <img src="<%= coll.tn %>" alt="<%= coll.title.data %>" />
                                 <img src="<%= coll.tn %>" alt="<%= coll.title.data %>" />
+                                <br/>
                             <% end %>
                             <% end %>
                             <%= coll.title.data %>
                             <%= coll.title.data %>
                             <%if coll.title.lang then %>
                             <%if coll.title.lang then %>
@@ -52,12 +53,13 @@
             </section>
             </section>
             <section id="obj_list">
             <section id="obj_list">
                 <h2>Recent artifacts</h2>
                 <h2>Recent artifacts</h2>
-                <ul>
+                <ul class="row slideshow">
                 <% for _, obj in ipairs(idx_data.objects) do %>
                 <% for _, obj in ipairs(idx_data.objects) do %>
-                    <li class="obj_link">
+                    <li class="column obj_link">
                         <a href="<%= obj.href %>">
                         <a href="<%= obj.href %>">
                             <%if obj.tn then %>
                             <%if obj.tn then %>
                                 <img src="<%= obj.tn %>" alt="<%= obj.title.data %>" />
                                 <img src="<%= obj.tn %>" alt="<%= obj.title.data %>" />
+                                <br/>
                             <% end %>
                             <% end %>
                             <%= obj.title.data %>
                             <%= obj.title.data %>
                             <%if obj.title.lang then %>
                             <%if obj.title.lang then %>

+ 11 - 11
templates/ores.html

@@ -10,6 +10,17 @@
                 <img class="title_icon" src="<%= icon_url %>" />
                 <img class="title_icon" src="<%= icon_url %>" />
                 <%= breadcrumbs[#breadcrumbs][2] -%>:&ensp;<%= fname %>
                 <%= breadcrumbs[#breadcrumbs][2] -%>:&ensp;<%= fname %>
             </h1>
             </h1>
+            <% if pres then %>
+            <section id="res_pres">
+            <% if mconf.gen.presentation_type == "image" then %>
+                <img src="<%= pres -%>" />
+            <%else %>
+                <a href="<%= pres -%>" download="<%= fname -%>">
+                    Download file
+                </a>
+            <% end %>
+            </section>
+            <% end %>
             <section id="res_lineage">
             <section id="res_lineage">
                 <h2>Classification</h2>
                 <h2>Classification</h2>
                 <p>
                 <p>
@@ -61,17 +72,6 @@
                 </dl>
                 </dl>
             </section>
             </section>
             <% end %>
             <% end %>
-            <% if pres then %>
-            <section id="res_pres">
-            <% if mconf.gen.presentation_type == "image" then %>
-                <img src="<%= pres -%>" />
-            <%else %>
-                <a href="<%= pres -%>" download="<%= fname -%>">
-                    Download file
-                </a>
-            <% end %>
-            </section>
-            <% end %>
         </main>
         </main>
         <footer></footer>
         <footer></footer>
     </body>
     </body>

+ 18 - 18
test/sample_submission/demo01/pkar_submission.csv

@@ -1,18 +1,18 @@
-"source_path","id","ext_id","content_type","label","alt_label","description","location","date","has_member","pref_rep"
-"demo_collection",,"coll0001","collection","My Demo Collection","My Beautiful  Collection","Some random stuff from my hard drive.",,2025-07-28,,"demo_collection/single_image/0685_04.jpg"
-,,,,,"My Aunt's Beautiful Collection","Old B/W photos.",,,,
-,,,,,,"More description to demonstrate how multi-valued fields are filled.",,,,
-,,,,,,"""id"" fields have been left blank to let the system auto-generate them.",,,,
-"demo_collection/demo_postcard",,"art0001","postcard","Example Postcard","This is an alternative label","Note that recto and verso representations have been named front and back, to emphasize that the ordering is not alphabetical.",,2025-06-10,,
-,,,,,,,,,,
-"demo_collection/demo_postcard/front",,,"brick","Recto",,"A windy spring day in Capo Falcone, Sardinia","Capo Falcone (SS) Italy",2004-04-12,,
-,,,,,,,"https://www.openstreetmap.org/#map=18/40.9696884/8.2020324",,,
-"demo_collection/demo_postcard/front/54321.jpg",,"file0001","still_image_file",,,,,,,
-"demo_collection/demo_postcard/back",,,"brick","Verso",,"Wandering around somewhere in Tirana, 2006.","Tirana, Albania",2006-05-05,,
-,,,,,,,"https://www.openstreetmap.org/relation/1250106",,,
-"demo_collection/demo_postcard/back/567890.jpg",,"file0002","still_image_file",,,,,,,
-"demo_collection/single_image",,"art0002","still_image","Preparing kebab at Aqil's during curfew.",,"Nothing much to do under curfew but cooking, eating, singing, dancing, playing cards, smoking water pipe, and occasionally playing soccer in the street when the Merkava didn't get in the way.","Nablus, Palestine",2002-08-16,,
-,,,,,,,"https://www.openstreetmap.org/#map=19/32.221597/35.260929",,,
-"demo_collection/single_image/0685_04.jpg",,"file0003","still_image_file",,,,,,,
-"coll2",,"coll0002","collection","Second collection",,"Collection made by reusing files from another collection.",,,"demo_collection/single_image/0685_04.jpg","demo_collection/single_image/0685_04.jpg"
-,,,,,,,,,"demo_collection/demo_postcard/front/54321.jpg",
+"source_path","ext_id","content_type","label","alt_label","description","location","date","has_member","pref_rep"
+"demo_collection","coll0001","collection","My Demo Collection","My Beautiful  Collection","Some random stuff from my hard drive.",,2025-07-28,,"demo_collection/single_image/0685_04.jpg"
+,,,,"My Aunt's Beautiful Collection","Old B/W photos.",,,,
+,,,,,"More description to demonstrate how multi-valued fields are filled.",,,,
+,,,,,"""id"" fields have been left blank to let the system auto-generate them.",,,,
+"demo_collection/demo_postcard","art0001","postcard","Example Postcard","This is an alternative label","Note that recto and verso representations have been named front and back, to emphasize that the ordering is not alphabetical.",,2025-06-10,,
+,,,,,,,,,
+"demo_collection/demo_postcard/front",,"brick","Recto",,"A windy spring day in Capo Falcone, Sardinia","Capo Falcone (SS) Italy",2004-04-12,,
+,,,,,,"https://www.openstreetmap.org/#map=18/40.9696884/8.2020324",,,
+"demo_collection/demo_postcard/front/54321.jpg","file0001","still_image_file",,,,,,,
+"demo_collection/demo_postcard/back",,"brick","Verso",,"Wandering around somewhere in Tirana, 2006.","Tirana, Albania",2006-05-05,,
+,,,,,,"https://www.openstreetmap.org/relation/1250106",,,
+"demo_collection/demo_postcard/back/567890.jpg","file0002","still_image_file",,,,,,,
+"demo_collection/single_image","art0002","still_image","Preparing kebab at Aqil's during curfew",,"Nothing much to do under curfew but cooking, eating, singing, dancing, playing cards, smoking water pipe, and occasionally playing soccer in the street when the Merkava didn't get in the way.","Nablus, Palestine",2002-08-16,,
+,,,,,,"https://www.openstreetmap.org/#map=19/32.221597/35.260929",,,
+"demo_collection/single_image/0685_04.jpg","file0003","still_image_file",,,,,,,
+"coll2","coll0002","collection","Second collection",,"Collection made by reusing files from another collection.",,,"demo_collection/single_image/0685_04.jpg","demo_collection/single_image/0685_04.jpg"
+,,,,,,,,"demo_collection/demo_postcard/front/54321.jpg",