diff --git a/fbfmaproom/assets/style.css b/fbfmaproom/assets/style.css index c2f8134f..09a5998b 100644 --- a/fbfmaproom/assets/style.css +++ b/fbfmaproom/assets/style.css @@ -26,7 +26,8 @@ body { #main_row { display: flex; flex-grow: 1; - min-height: 0; /* otherwise it gets sized to fit the table content and overflows the viewport. */ + min-height: 0; + /* otherwise it gets sized to fit the table content and overflows the viewport. */ } #lcol { @@ -102,7 +103,8 @@ table.supertable { display: block; } -table.supertable td, table.supertable th { +table.supertable td, +table.supertable th { border-right-style: solid; border-right-width: 1px; border-right-color: rgb(200, 200, 200); @@ -174,3 +176,35 @@ table.supertable tbody { .cell-excluded { background-color: rgb(150, 150, 150); } + +#season_links .btn-primary { + line-height: 22px; + width: 100%; + text-align: left; + padding: 10px; + border-radius: 4px; + font: 14px / 16px Arial, Helvetica, sans-serif; + --bs-btn-color: #333; + --bs-btn-bg: white; + --bs-btn-border-color: #ccc; + --bs-btn-hover-border-color: #ccc; + --bs-btn-hover-bg: white; + --bs-btn-hover-color: #333; + --bs-btn-active-color: #333; + --bs-btn-active-border-color: #ccc; + --bs-btn-active-bg: white; + --bs-btn-disabled-color: #333; + --bs-btn-disabled-bg: white; +} + +#season_links .dropdown-toggle::after { + float: right; + margin: 5px; + border-width: 5px 5px 2.5px; + color: #999; +} + +#season_links .dropdown-item { + --bs-dropdown-link-active-bg: #cfe2ff; + --bs-dropdown-link-active-color: black; +} \ No newline at end of file diff --git a/fbfmaproom/fbflayout.py b/fbfmaproom/fbflayout.py index bd657f7f..3544ee16 100644 --- a/fbfmaproom/fbflayout.py +++ b/fbfmaproom/fbflayout.py @@ -226,13 +226,14 @@ def control_layout(): clearable=False, ), ), - + # TODO: A hidden dropdown is used to store the season variable. + # This can be removed once season is refactored to be contained in a single page + html.Div(dcc.Dropdown(id="season"), style={"display": "none"}), control( "Season", "The rainy season being forecasted", - dcc.Dropdown( - id="season", - clearable=False, + dbc.DropdownMenu( + id="season_links", ), ), diff --git a/fbfmaproom/fbfmaproom-sample.yaml b/fbfmaproom/fbfmaproom-sample.yaml index e91f0a5d..296b5033 100644 --- a/fbfmaproom/fbfmaproom-sample.yaml +++ b/fbfmaproom/fbfmaproom-sample.yaml @@ -358,7 +358,10 @@ countries: pct: quantile colormap: pne_25 is_poe: no - + subpages: + DJF: "madagascar" + NDJ: "madagascar-ndj" + OND: "madagascar-ond" seasons: season1: label: DJF @@ -519,6 +522,10 @@ countries: pct: quantile colormap: pne_25 is_poe: no + subpages: + DJF: "madagascar" + NDJ: "madagascar-ndj" + OND: "madagascar-ond" seasons: season1: label: NDJ @@ -689,7 +696,10 @@ countries: pct: quantile colormap: pne_25 is_poe: no - + subpages: + DJF: "madagascar" + NDJ: "madagascar-ndj" + OND: "madagascar-ond" seasons: season1: label: OND diff --git a/fbfmaproom/fbfmaproom.py b/fbfmaproom/fbfmaproom.py index 8989ed32..63440d67 100644 --- a/fbfmaproom/fbfmaproom.py +++ b/fbfmaproom/fbfmaproom.py @@ -778,6 +778,8 @@ def country(pathname: str) -> str: Output("map", "zoom"), Output("season", "options"), Output("season", "value"), + Output("season_links", "children"), + Output("season_links", "label"), Output("mode", "options"), Output("mode", "value"), Output("predictand", "options"), @@ -794,7 +796,7 @@ def country(pathname: str) -> str: Input("location", "pathname"), State("location", "search"), ) -def initial_setup(pathname, qstring): +def initial_setup(pathname: str, qstring: str): country_key = country(pathname) c = CONFIG["countries"][country_key] @@ -805,6 +807,15 @@ def initial_setup(pathname, qstring): ) for k in sorted(c["seasons"].keys()) ] + + subpages = c.get("subpages", {"DEFAULT": country_key}) + season_link_options = [ + dbc.DropdownMenuItem(subpage, href=f"{PFX}/{subpage_link}", active=(subpage_link == country_key)) + for subpage, subpage_link in subpages.items() + ] + active_seasons = [subpage for subpage, subpage_link in subpages.items() if subpage_link==country_key] + active_season = active_seasons[0] if len(active_seasons) > 0 else "" + cx, cy = c["center"] mode_options = [ @@ -894,6 +905,8 @@ def initial_setup(pathname, qstring): c["zoom"], season_options, season_value, + season_link_options, + active_season, mode_options, mode_value, predictand_options, diff --git a/pingrid/impl.py b/pingrid/impl.py index 1650b451..20af3351 100644 --- a/pingrid/impl.py +++ b/pingrid/impl.py @@ -1277,7 +1277,7 @@ def client_side_error(e): REQUIRED = object() -def parse_arg(name, conversion=str, default=REQUIRED, qstring=None): +def parse_arg(name: str, conversion=str, default=REQUIRED, qstring: Optional[str] = None): '''Stricter version of flask.request.args.get. Raises an exception in cases where args.get ignores the problem and silently falls back on a default behavior: