diff --git a/core/constants.py b/core/constants.py index 0a8ce8a..15c84e7 100644 --- a/core/constants.py +++ b/core/constants.py @@ -4,7 +4,7 @@ from data.activity import Activity from data.band import Band # General software -SOFTWARE_VERSION = "2.1" +SOFTWARE_VERSION = "2.2-pre" # HTTP headers used for spot providers that use HTTP HTTP_HEADERS = {"User-Agent": f"Spothole v{SOFTWARE_VERSION} (operated by {SERVER_OWNER_CALLSIGN})"} @@ -13,10 +13,10 @@ HAMQTH_PRG = f"Spothole v{SOFTWARE_VERSION} operated by {SERVER_OWNER_CALLSIGN}" # Activities ACTIVITIES = [ Activity( - name="AMSAT", + name="Satellite", comment_names=[], - description="Amateur Radio Satellites", - sig_type=ActivityType.WORLDWIDE, + description="Amateur Radio Satellite", + sig_type=ActivityType.TRADITIONAL, icon="fa-satellite", refs_globally_unique=False, ), @@ -24,7 +24,7 @@ ACTIVITIES = [ name="EME", comment_names=[], description="Moonbounce", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.TRADITIONAL, icon="fa-moon", refs_globally_unique=False, ), @@ -32,7 +32,7 @@ ACTIVITIES = [ name="POTA", comment_names=["POTA"], description="Parks on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.PARK, ref_regex=r"[A-Z]{2}\-\d{4,5}|K\-TEST", icon="fa-tree", @@ -42,7 +42,7 @@ ACTIVITIES = [ name="SOTA", comment_names=["SOTA"], description="Summits on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.SUMMIT, ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}", icon="fa-mountain-sun", @@ -52,7 +52,7 @@ ACTIVITIES = [ name="WWFF", comment_names=["WWFF"], description="World Wide Flora & Fauna", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.PARK, ref_regex=r"[A-Z0-9]{1,3}FF\-\d{4}", icon="fa-seedling", @@ -62,7 +62,7 @@ ACTIVITIES = [ name="GMA", comment_names=["GMA"], description="Global Mountain Activity", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.SUMMIT, ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}", icon="fa-person-hiking", @@ -72,7 +72,7 @@ ACTIVITIES = [ name="WWBOTA", comment_names=["WWBOTA", "BOTA"], description="Worldwide Bunkers on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.BUNKER, ref_regex=r"B\/[A-Z0-9]{1,3}\-\d{3,4}", icon="fa-radiation", @@ -82,7 +82,7 @@ ACTIVITIES = [ name="HEMA", comment_names=["HEMA"], description="HuMPs Excluding Marilyns Award", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.SUMMIT, ref_regex=r"[A-Z0-9]{1,3}\/[A-Z]{3}\-\d{3}", icon="fa-mound", @@ -92,7 +92,7 @@ ACTIVITIES = [ name="IOTA", comment_names=["IOTA"], description="Islands on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.ISLAND, ref_regex=r"[A-Z]{2}\-\d{3}", icon="fa-book-atlas", @@ -102,7 +102,7 @@ ACTIVITIES = [ name="GMA Islands", comment_names=[], description="Global Mountain Activity - Islands", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.ISLAND, ref_regex=r"(([A-Z]{2}\-\d{3})|([A-Z0-9]{1,3}\/[A-Z]{2}\-\d{3}))", icon="fa-person-hiking", @@ -112,7 +112,7 @@ ACTIVITIES = [ name="ARLHS", comment_names=["ARLHS"], description="Amateur Radio Lighthouse Society", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.LIGHTHOUSE, ref_regex=r"[A-Z]{3}[\- ]\d{3,4}", icon="fa-house-flood-water", @@ -142,7 +142,7 @@ ACTIVITIES = [ name="SIOTA", comment_names=["SIOTA"], description="Silos on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.SILO, ref_regex=r"[A-Z]{2}\-[A-Z]{3}\d", icon="fa-wheat-awn", @@ -152,7 +152,7 @@ ACTIVITIES = [ name="WCA", comment_names=["WCA"], description="World Castles Award", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.CASTLE, ref_regex=r"[A-Z0-9]{1,3}\-\d{5}", icon="fa-chess-rook", @@ -184,7 +184,7 @@ ACTIVITIES = [ name="BOTA", comment_names=[], description="Beaches on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.BEACH, icon="fa-umbrella-beach", refs_globally_unique=False, @@ -215,7 +215,7 @@ ACTIVITIES = [ name="LLOTA", comment_names=["LLOTA"], description="Lagos y Lagunas on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.LAKE, ref_regex=r"LL[A-Z]{2}\-\d{4}", icon="fa-water", @@ -225,7 +225,7 @@ ACTIVITIES = [ name="Towers", comment_names=["TOTA"], description="Towers on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.TOWER, ref_regex=r"[A-Z]{2,3}R\-\d{4}", icon="fa-tower-observation", @@ -235,7 +235,7 @@ ACTIVITIES = [ name="Tiles", comment_names=[], description="Tiles on the Air", - sig_type=ActivityType.WORLDWIDE, + sig_type=ActivityType.ADVENTURE, ref_type=ActivityRefType.GRID, ref_regex=r"[A-Za-z]{2}[0-9]{2}[A-Za-z]{2}", icon="fa-square", diff --git a/core/enums.py b/core/enums.py index 5eda1d5..9d1c70f 100644 --- a/core/enums.py +++ b/core/enums.py @@ -124,7 +124,8 @@ class AlertType(str, Enum): class ActivityType(str, Enum): """Type of an activity. Used to group them in the web UI.""" - WORLDWIDE = "WORLDWIDE" + TRADITIONAL = "TRADITIONAL" + ADVENTURE = "ADVENTURE" REGIONAL = "REGIONAL" EVENT = "EVENT" diff --git a/pyproject.toml b/pyproject.toml index b399009..0c60af0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "spothole" -version = "2.1" +version = "2.2-pre" authors = [ { name = "Ian Renton", email = "ian@ianrenton.com" }, ] diff --git a/static/apidocs/openapi.yml b/static/apidocs/openapi.yml index f0ecbcc..4a03b3e 100644 --- a/static/apidocs/openapi.yml +++ b/static/apidocs/openapi.yml @@ -917,10 +917,11 @@ components: ActivityType: type: string enum: - - WORLDWIDE + - TRADITIONAL + - ADVENTURE - REGIONAL - EVENT - example: WORLDWIDE + example: TRADITIONAL ActivityNameIncludingNoSig: oneOf: @@ -1597,16 +1598,16 @@ components: sig_type: type: boolean description: > - Whether the activity is worldwide, regional, or for a specific event. Generally for Spothole's own - internal use, clients probably won't need this. Used to group them in the web UI. Still named - "sig_type" in the API for backwards compatibility. + Whether the activity is traditional (e.g. EME), adventure (e.g. POTA), regional (e.g. WAB), or for a + specific event (e.g. MOTA). Generally for Spothole's own internal use, clients probably won't need this. + Used to group them in the web UI. Still named "sig_type" in the API for backwards compatibility. $ref: "#/components/schemas/ActivityType" comment_names: type: array description: > Names by which this activity may be referred to in cluster spot comments. Most activities have a single entry matching their programme name (e.g. ["POTA"]), but some have none (where - the name is ambiguous with other activities, such as Tiles and Toilets on the Air) or multiple + the name is ambiguous with other activities, such as "TOTA" for Tiles and Toilets on the Air) or multiple entries (e.g. WWBOTA accepts both "WWBOTA" and "BOTA" since the latter is often used). items: type: string diff --git a/static/css/style.css b/static/css/style.css index ec2351f..fc03f35 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -279,6 +279,51 @@ div#map { } +/* COLLAPSIBLE FILTER SECTIONS (e.g. Activities panel) */ + +ul.filter-section-list { + margin-bottom: 0; +} + +button.btn-toggle { + display: block; + width: 100%; + padding: .25rem 0; + font-weight: 600; + text-align: left; + color: var(--bs-emphasis-color); + background-color: transparent; + border: 0; +} + +button.btn-toggle:hover, +button.btn-toggle:focus { + background-color: transparent; + box-shadow: none; +} + +button.btn-toggle::before { + display: inline-block; + width: 1.25em; + line-height: 0; + content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e"); + transition: transform .35s ease; + transform-origin: .5em 50%; +} + +[data-bs-theme="dark"] button.btn-toggle::before { + content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%28255,255,255,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e"); +} + +button.btn-toggle[aria-expanded="true"]::before { + transform: rotate(90deg); +} + +div.filter-section-body { + padding-left: 1.25em; +} + + /* BANDS PANEL */ div#bands-container { diff --git a/static/js/spotsbandsandmap.js b/static/js/spotsbandsandmap.js index 2fd34ca..ca06e73 100644 --- a/static/js/spotsbandsandmap.js +++ b/static/js/spotsbandsandmap.js @@ -38,33 +38,61 @@ function setHamHFBandToggles() { filtersUpdated(); } +// Generate a collapsable section for the activities filter card, and append it to the given list. The section is +// expanded by default if isExpanded is true. +function appendActivityFilterSection($list, sectionId, heading, isExapanded, buildBody) { + const collapseId = `activity-options-${sectionId}-collapse`; + const $li = $('