ssod / ui.R
alexdum's picture
Clean initial commit for SSOD Hugging Face Space
ae2229b
Raw
History Blame Contribute Delete
7.12 kB
# ui.R
ui <- page_navbar(
id = "main_nav",
header = tagList(
useShinyjs(),
tags$head(
# Security & Privacy compliance
tags$meta(name = "referrer", content = "strict-origin-when-cross-origin"),
tags$meta(`http-equiv` = "Content-Security-Policy", content = "upgrade-insecure-requests;"),
# Performance Preloads
tags$link(rel = "preload", href = "styles.css", as = "style"),
tags$link(rel = "preload", href = "app.js", as = "script"),
# Include external CSS and JS from www/ folder
tags$link(rel = "stylesheet", type = "text/css", href = "styles.css"),
tags$script(src = "app.js"),
# Layer Control Interactions
tags$script(HTML("
$(document).ready(function() {
var $layerControl = $('.map-layer-control');
$layerControl.on('mouseenter', function() {
$(this).addClass('expanded');
});
$layerControl.on('mouseleave', function() {
$(this).removeClass('expanded');
});
$layerControl.on('change', 'input[type=\\'radio\\']', function() {
$layerControl.removeClass('expanded');
});
});
"))
),
# Frozen overlay div
div(
class = "frozen-overlay",
div(
class = "frozen-overlay-content",
tags$button(class = "frozen-overlay-close", "×", title = "Cancel loading"),
p(class = "frozen-overlay-station", ""),
div(class = "spinner-border text-primary", role = "status"),
p(class = "frozen-overlay-message", "Loading data...")
)
)
),
title = "SSOD Explorer",
theme = bs_theme(version = 5, bootswatch = "cosmo"),
sidebar = sidebar(
title = "Filters",
div(
style = "display: flex; align-items: center; gap: 8px;",
tags$label("Select Country", `for` = "country"),
tooltip(
bsicons::bs_icon("info-circle", size = "1em"),
"Filter stations by country. Leave empty to show all stations worldwide."
)
),
selectInput("country", label = NULL, choices = NULL, multiple = TRUE),
div(
style = "display: flex; align-items: center; gap: 8px;",
tags$label("Find Station"),
tooltip(
bsicons::bs_icon("search", size = "1em"),
"Search for a station by name or ID within the current filters."
)
),
selectizeInput("station_selector", label = NULL, choices = NULL, multiple = FALSE, options = list(placeholder = "Type to search...")),
div(
style = "display: flex; align-items: center; gap: 8px;",
tags$label("Select Date Range"),
tooltip(
bsicons::bs_icon("info-circle", size = "1em"),
"Filter stations that have data overlapping with this date range. This also sets the window for plots, and is responsible for the length of the data parsed."
)
),
dateRangeInput("date_range",
label = NULL,
start = default_start_date, end = default_end_date,
min = "1800-01-01", max = Sys.Date()
),
hr(),
div(
style = "display: flex; align-items: center; gap: 8px;",
downloadButton("download_stations", "Download Stations (Excel)", class = "btn-success", icon = icon("file-excel")),
tooltip(
bsicons::bs_icon("info-circle", size = "1em"),
"Export the metadata of stations filtered by the current zoom level (Excel)."
)
),
hr(),
textOutput("station_count_filtered"),
hr(),
p("Data source: NCEI SSOD daily"),
hr(),
tags$small("Tip: Click map points to view detailed weather plots.")
),
nav_panel(
title = "Map View",
div(
class = "outer",
maplibreOutput("map", height = "100%", width = "100%"),
# Map loading spinner (hidden by JS once map loads)
div(
id = "map-loading-spinner",
class = "map-loading-overlay",
div(
class = "map-loading-content",
div(class = "map-spinner"),
tags$p("Loading base map...")
)
),
# Layer Control Panel (Collapsible)
absolutePanel(
top = 130, left = 10,
class = "map-layer-control",
style = "z-index: 1000;",
div(class = "control-icon", icon("layer-group")),
div(
class = "control-content",
radioButtons(
inputId = "basemap",
label = "Basemap",
choices = c(
"OpenFreeMap Positron" = "ofm_positron",
"OpenFreeMap Bright" = "ofm_bright",
"Satellite (Sentinel-2)" = "sentinel"
),
selected = "ofm_positron"
),
hr(style = "margin: 8px 0;"),
checkboxInput(
inputId = "show_labels",
label = "Show Labels",
value = TRUE
)
)
),
# Home Button Overlay
absolutePanel(
id = "zoom_home_panel",
top = 80, left = 10,
actionButton("zoom_home", bsicons::bs_icon("house-fill"), class = "btn-home", title = "Zoom to all stations")
)
)
),
nav_panel(
title = "Stations Info",
div(
style = "margin-bottom: 10px; color: #666; display: flex; align-items: center; gap: 6px;",
bsicons::bs_icon("info-circle"),
"Double-click a row to load station data and view the dashboard."
),
DT::dataTableOutput("table")
),
nav_panel(
title = "Dashboard",
value = "Dashboard",
conditionalPanel(
condition = "!output.station_ready",
div(
style = "height: 600px; display: flex; align-items: center; justify-content: center;",
p("Select a station from the map or the Stations Info table to view the dashboard.", style = "color: #999;")
)
),
conditionalPanel(
condition = "output.station_ready",
div(
class = "h-100 overflow-auto p-3",
uiOutput("station_info_header"),
navset_card_pill(
id = "dashboard_subtabs",
nav_panel(
title = "Plots",
uiOutput("details_tabs")
),
nav_panel(
title = "Data",
div(
style = "margin-top: 10px;",
bslib::card(
height = "calc(100vh - 280px)",
full_screen = TRUE,
bslib::card_body(
div(
style = "text-align: right; margin-bottom: 10px;",
downloadButton("download_daily", "Export Data", class = "btn-sm btn-outline-success", icon = icon("file-excel"))
),
DT::dataTableOutput("daily_summary_main")
)
)
)
)
)
)
)
),
nav_spacer(),
nav_item(
tooltip(
tags$a(
id = "fullscreen_toggle",
href = "#",
onclick = "toggleFullScreen(); return false;",
style = "display: flex; align-items: center; color: rgba(0,0,0,0.55); padding: 0.5rem 1rem; text-decoration: none;",
bsicons::bs_icon("arrows-fullscreen", size = "1.2rem")
),
"Toggle Fullscreen",
placement = "bottom"
)
)
)