368 lines
21 KiB
Plaintext
368 lines
21 KiB
Plaintext
{*
|
|
* Amsterdam Web Communities System
|
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*}
|
|
<div class="p-4">
|
|
<!-- Page Title with Tabs -->
|
|
<div class="mb-6">
|
|
<div class="flex items-baseline gap-2">
|
|
<h1 class="text-blue-800 text-4xl font-bold">Find:</h1>
|
|
<nav class="text-blue-800 text-2xl">
|
|
{{ if mode == "COM" }}
|
|
<span class="font-bold">Communities</span>
|
|
{{ else }}
|
|
<a href="/find?mode=COM" class="text-blue-700 hover:text-blue-900">Communities</a>
|
|
{{ end }}
|
|
<span class="mx-2">|</span>
|
|
{{ if mode == "USR" }}
|
|
<span class="font-bold">Users</span>
|
|
{{ else }}
|
|
<a href="/find?mode=USR" class="text-blue-700 hover:text-blue-900">Users</a>
|
|
{{ end }}
|
|
<span class="mx-2">|</span>
|
|
{{ if isset(catIsPresent) }}
|
|
{{ if mode == "CAT" }}
|
|
<span class="font-bold">Categories</span>
|
|
{{ else }}
|
|
<a href="/find?mode=CAT" class="text-blue-700 hover:text-blue-900">Categories</a>
|
|
{{ end }}
|
|
<span class="mx-2">|</span>
|
|
{{ end }}
|
|
{{ if mode == "PST" }}
|
|
<span class="font-bold">Posts</span>
|
|
{{ else }}
|
|
<a href="/find?mode=PST" class="text-blue-700 hover:text-blue-900">Posts</a>
|
|
{{ end }}
|
|
</nav>
|
|
</div>
|
|
<hr class="border-2 border-gray-400 w-4/5 mt-2 mb-6">
|
|
</div>
|
|
|
|
{{ if isset(errorMessage) }}
|
|
<!-- Error Message Banner -->
|
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-6" id="error-banner">
|
|
<div class="flex items-center">
|
|
<div class="flex-shrink-0">
|
|
<span class="text-red-500 text-xl">⚠️</span>
|
|
</div>
|
|
<div class="ml-3">
|
|
<p class="text-sm font-medium" id="error-message">{{ CapitalizeString(errorMessage) }}.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
|
|
<!-- Search Form -->
|
|
<div class="max-w-3xl mb-8">
|
|
<form method="POST" action="/find">
|
|
<input type="hidden" name="mode" value="{{ mode }}">
|
|
<input type="hidden" name="ofs" value="0">
|
|
|
|
<div class="bg-gray-50 p-6 rounded-lg">
|
|
{{ if mode == "COM" }}
|
|
<h2 class="text-xl font-bold text-black mb-4">Find Communities:</h2>
|
|
{{ else if mode == "USR" }}
|
|
<h2 class="text-xl font-bold text-black mb-4">Find Users:</h2>
|
|
{{ else if mode == "CAT" }}
|
|
<h2 class="text-xl font-bold text-black mb-4">Find Categories:</h2>
|
|
{{ else if mode == "PST" }}
|
|
<h2 class="text-xl font-bold text-black mb-4">Find Posts:</h2>
|
|
{{ end }}
|
|
|
|
<div class="space-y-4">
|
|
{{ if mode == "COM" || mode == "USR" }}
|
|
<!-- Field Selection -->
|
|
<div class="flex items-center gap-2 text-sm">
|
|
{{ if mode == "COM" }}
|
|
<span class="text-black">Display all communities whose</span>
|
|
{{ else if mode == "USR" }}
|
|
<span class="text-black">Display all users whose</span>
|
|
{{ end }}
|
|
<select name="field"
|
|
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
{{ if mode == "COM" }}
|
|
<option value="name" {{ if field == "name" }}selected{{ end }}>name</option>
|
|
<option value="synopsis"{{ if field == "synopsis" }}selected{{ end }}>synopsis</option>
|
|
{{ else if mode == "USR" }}
|
|
<option value="name" {{ if field == "name" }}selected{{ end }}>user name</option>
|
|
<option value="descr"{{ if field == "descr" }}selected{{ end }}>description</option>
|
|
<option value="first"{{ if field == "first" }}selected{{ end }}>first name</option>
|
|
<option value="last"{{ if field == "last" }}selected{{ end }}>last name</option>
|
|
{{ end }}
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Search Criteria -->
|
|
<div class="flex items-center gap-2 text-sm flex-wrap">
|
|
<select name="oper"
|
|
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="st" {{ if oper == "st" }}selected{{ end }}>starts with the string</option>
|
|
<option value="in" {{ if oper == "in" }}selected{{ end }}>contains the string</option>
|
|
<option value="re" {{ if oper == "re" }}selected{{ end }}>matches the regular expression</option>
|
|
</select>
|
|
<input type="text" name="term" size="32" maxlength="255" value="{{ term }}"
|
|
placeholder="Enter search term..."
|
|
class="flex-1 min-w-64 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
{{ else if mode == "CAT" }}
|
|
<input type="hidden" name="field" value="name">
|
|
<!-- Field Selection -->
|
|
<div class="flex items-center gap-2 text-sm">
|
|
<span class="text-black">Display all categories whose name</span>
|
|
<select name="oper"
|
|
class="px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
<option value="st" {{ if oper == "st" }}selected{{ end }}>starts with the string</option>
|
|
<option value="in" {{ if oper == "in" }}selected{{ end }}>contains the string</option>
|
|
<option value="re" {{ if oper == "re" }}selected{{ end }}>matches the regular expression</option>
|
|
</select>
|
|
</div>
|
|
<!-- Search Criteria -->
|
|
<div class="flex items-center gap-2 text-sm flex-wrap">
|
|
<input type="text" name="term" size="32" maxlength="255" value="{{ term }}"
|
|
placeholder="Enter search term..."
|
|
class="flex-1 min-w-64 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
{{ else if mode == "PST" }}
|
|
<input type="hidden" name="field" value="name">
|
|
<input type="hidden" name="oper" value="in">
|
|
<!-- Keyword search criteria -->
|
|
<div class="flex items-center gap-2 text-sm">
|
|
<span class="text-black">Keywords:</span>
|
|
<input type="text" name="term" size="32" maxlength="255" value="{{ term }}"
|
|
placeholder="Enter search term..."
|
|
class="flex-1 min-w-64 px-3 py-2 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
{{ end }}
|
|
|
|
<!-- Search Button -->
|
|
<div>
|
|
<button type="submit" name="search"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
|
Search
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Category Listing -->
|
|
{{ if isset(displayCats) }}
|
|
<div class="max-w-3xl">
|
|
<hr class="border-gray-400 mb-4">
|
|
|
|
<h2 class="text-lg font-bold text-black mb-4">
|
|
Category:
|
|
{{ if catid == -1 }}
|
|
Top
|
|
{{ else }}
|
|
<a href="/find?mode=COM&catid=-1" class="text-blue-700 hover:text-blue-900 font-bold">Top</a>
|
|
{{ end }}
|
|
{{ last := len(catHierarchy) - 1 }}
|
|
{{ range i, cat := catHierarchy }}
|
|
:
|
|
{{ if i == last }}
|
|
{{ cat.Name }}
|
|
{{ else }}
|
|
<a href="/find?mode=COM&catid={{ cat.CatId }}"
|
|
class="text-blue-700 hover:text-blue-900 font-bold">{{ cat.Name }}</a>
|
|
{{ end }}
|
|
{{ end }}
|
|
</h2>
|
|
|
|
{{ if len(catSubs) > 0 }}
|
|
<div class="bg-gray-50 p-6 rounded-lg">
|
|
<h3 class="text-base font-bold text-black mb-4">Subcategories:</h3>
|
|
<div class="grid grid-cols-1 md:grid-cols-1 gap-1">
|
|
{{ range _, cat := catSubs }}
|
|
{{ if !cat.HideDirectory || showHiddenCat }}
|
|
<div class="flex items-start gap-1">
|
|
<span class="text-sm pt-0.5">🟣</span>
|
|
<a href="/find?mode=COM&catid={{ cat.CatId }}"
|
|
class="text-blue-700 hover:text-blue-900 font-bold text-sm">{{ cat.Name }}</a>
|
|
{{ if cat.SymLink != -1 }}<span class="text-sm pt-0.5">🔗</span>{{ end }}
|
|
</div>
|
|
{{ end }}
|
|
{{ end }}
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
</div>
|
|
{{ end }}
|
|
|
|
{{ if isset(resultHeader) }}
|
|
<!-- Search results -->
|
|
<hr class="border-gray-400 mb-4">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<div class="text-sm text-black font-bold">{{ resultHeader }}</div>
|
|
</div>
|
|
{{ if isset(resultList) }}
|
|
{{ if mode == "PST" && len(resultList) > 0 }}
|
|
<div class="overflow-x-auto">
|
|
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
|
<table class="w-full">
|
|
<thead class="bg-gray-100 border-b-2 border-gray-300">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Post Link</th>
|
|
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Author</th>
|
|
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider whitespace-nowrap">Post Date</th>
|
|
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Lines</th>
|
|
<th class="px-4 py-3 text-left text-xs font-bold text-gray-700 uppercase tracking-wider">Preview</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200">
|
|
{{ range _, rx := resultList }}
|
|
<tr class="hover:bg-blue-50">
|
|
<td class="px-4 py-3 text-sm">
|
|
<a href="/go/{{ rx.PostLink }}" class="text-blue-700 hover:text-blue-900 font-mono">{{ rx.PostLink }}</a>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm">
|
|
<a href="/user/{{ rx.Author }}" class="text-blue-700 hover:text-blue-900">{{ rx.Author }}</a>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm whitespace-nowrap text-gray-600">{{ DisplayDateTime( rx.PostDate, .) }}</td>
|
|
<td class="px-4 py-3 text-sm text-gray-600">{{ rx.Lines }}</td>
|
|
<td class="px-4 py-3 text-sm text-gray-600 italic">{{ rx.Excerpt }}</td>
|
|
</tr>
|
|
{{ end }}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{{ if isset(resultShowPrev) || isset(resultShowNext) }}
|
|
<!-- Bottom Navigation -->
|
|
<div class="flex justify-end mt-6">
|
|
<form method="POST" action="/find">
|
|
<input type="hidden" name="mode" value="{{ mode }}"/>
|
|
<input type="hidden" name="ofs" value="{{ ofs }}"/>
|
|
<input type="hidden" name="field" value="{{ field }}"/>
|
|
<input type="hidden" name="oper" value="{{ oper }}"/>
|
|
<input type="hidden" name="term" value="{{ term }}"/>
|
|
{{ if isset(resultShowPrev) }}
|
|
<button type="submit" name="prev"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
|
⏪ Prev
|
|
</button>
|
|
{{ end }}
|
|
{{ if isset(resultShowNext) }}
|
|
<button type="submit" name="next"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
|
Next ⏩
|
|
</button>
|
|
{{ end }}
|
|
</form>
|
|
</div>
|
|
{{ end }}
|
|
{{ else }}
|
|
<!-- Results List -->
|
|
<div class="bg-gray-50 p-6 rounded-lg">
|
|
<div class="space-y-4">
|
|
{{ range _, rx := resultList }}
|
|
{{ if mode == "COM" }}
|
|
<!-- Community Result -->
|
|
<div class="flex items-start gap-3">
|
|
<span class="text-sm pt-0.5 flex-shrink-0">🟣</span>
|
|
<div class="flex-1">
|
|
<div class="mb-2">
|
|
<a href="/comm/{{ rx.Alias }}/profile"
|
|
class="text-blue-700 hover:text-blue-900 font-bold text-base">{{ rx.Name }}</a>
|
|
</div>
|
|
<div class="text-sm text-gray-700 space-y-1">
|
|
<div>
|
|
<span class="font-medium">Host:</span>
|
|
{{ h := CommunityHost(rx, .) }}
|
|
<a href="/user/{{ h.Username }}" class="text-blue-700 hover:text-blue-900">{{ h.Username }}</a>
|
|
<span class="mx-2">-</span>
|
|
{{ n := DisplayMemberCount(rx, .) }}
|
|
{{ if n == 1 }}
|
|
<span>1 member</span>
|
|
{{ else }}
|
|
<span>{{ n }} members</span>
|
|
{{ end }}
|
|
</div>
|
|
<div>
|
|
<span class="font-medium">Latest activity:</span> {{ DisplayActivity(rx.LastAccess, .)}}
|
|
</div>
|
|
<div class="italic text-gray-600 mt-2">{{ rx.Synopsis }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{ else if mode == "USR" }}
|
|
<!-- User Result -->
|
|
<div class="flex items-start gap-3">
|
|
<span class="text-sm pt-0.5 flex-shrink-0">🟣</span>
|
|
<div class="flex-1">
|
|
<div class="mb-2">
|
|
<a href="/user/{{ rx.Username }}"
|
|
class="text-blue-700 hover:text-blue-900 font-bold text-base">{{ rx.Username }}</a>
|
|
</div>
|
|
<div class="text-sm text-gray-700 space-y-1">
|
|
<div>
|
|
{{ ci := UserContactInfo(rx, .) }}
|
|
{{ DisplayFullName(ci) }}, from {{ ci.Locality }}, {{ ci.Region }} {{ ci.Country }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{ else if mode == "CAT" }}
|
|
<!-- Category Result -->
|
|
<div class="flex items-start gap-3">
|
|
<span class="text-sm pt-0.5 flex-shrink-0">🟣</span>
|
|
<div class="flex-1 mb-2">
|
|
<a href="/find?mode=COM&catid={{ rx.CatId }}"
|
|
class="text-blue-700 hover:text-blue-900 font-bold text-base">{{ DisplayExpandCat(rx, .) }}</a>
|
|
</div>
|
|
</div>
|
|
{{ end }}
|
|
{{ end }}
|
|
</div>
|
|
{{ if isset(resultShowPrev) || isset(resultShowNext) }}
|
|
<div class="flex justify-center gap-4 mt-6">
|
|
{{ if isset(resultFromDirectory) }}
|
|
{{ if isset(resultShowPrev) }}
|
|
<a href="/find?mode=COM&catid={{ catid }}&ofs={{ ofs - 1 }}"
|
|
class="inline-block bg-blue-600 hover:bg-blue-700 text-white px-4 py-1 rounded text-xs font-medium transition-colors">
|
|
⏪ Prev
|
|
</a>
|
|
{{ end }}
|
|
{{ if isset(resultShowNext) }}
|
|
<a href="/find?mode=COM&catid={{ catid }}&ofs={{ ofs + 1 }}"
|
|
class="inline-block bg-blue-600 hover:bg-blue-700 text-white px-4 py-1 rounded text-xs font-medium transition-colors">
|
|
Next ⏩
|
|
</a>
|
|
{{ end }}
|
|
{{ else }}
|
|
<form method="POST" action="/find">
|
|
<input type="hidden" name="mode" value="{{ mode }}"/>
|
|
<input type="hidden" name="ofs" value="{{ ofs }}"/>
|
|
<input type="hidden" name="field" value="{{ field }}"/>
|
|
<input type="hidden" name="oper" value="{{ oper }}"/>
|
|
<input type="hidden" name="term" value="{{ term }}"/>
|
|
{{ if isset(resultShowPrev) }}
|
|
<button type="submit" name="prev"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
|
⏪ Prev
|
|
</button>
|
|
{{ end }}
|
|
{{ if isset(resultShowNext) }}
|
|
<button type="submit" name="next"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-8 py-2 rounded font-medium transition-colors">
|
|
Next ⏩
|
|
</button>
|
|
{{ end }}
|
|
</form>
|
|
{{ end }}
|
|
</div>
|
|
{{ end }}
|
|
</div>
|
|
{{ end }}
|
|
{{ end }}
|
|
{{ end }}
|
|
</div>
|