| |
| ui <- page_navbar( |
| id = "main_nav", |
| header = tagList( |
| useShinyjs(), |
| tags$head( |
| |
| tags$meta(name = "referrer", content = "strict-origin-when-cross-origin"), |
| tags$meta(`http-equiv` = "Content-Security-Policy", content = "upgrade-insecure-requests;"), |
| |
| tags$link(rel = "preload", href = "styles.css", as = "style"), |
| tags$link(rel = "preload", href = "app.js", as = "script"), |
| |
| tags$link(rel = "stylesheet", type = "text/css", href = "styles.css"), |
| tags$script(src = "app.js"), |
| |
| 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'); |
| }); |
| }); |
| ")) |
| ), |
| |
| 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%"), |
| |
| div( |
| id = "map-loading-spinner", |
| class = "map-loading-overlay", |
| div( |
| class = "map-loading-content", |
| div(class = "map-spinner"), |
| tags$p("Loading base map...") |
| ) |
| ), |
|
|
| |
| 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 |
| ) |
| ) |
| ), |
|
|
| |
| 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" |
| ) |
| ) |
| ) |
|
|