Oziblue
  • Rencontre de dessin
  • Rolodex
  • A propos

Rolodex

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 700

## file: ui.R
library(shiny)

ui <- navbarPage(
  title = "Rolodex",
  
  # -------------------- PAGE 1: RECIPES --------------------
  tabPanel(
    "Recipe Rolodex",
    sidebarLayout(
      sidebarPanel(
        selectInput("course_filter", "Filter by Course",
                    choices = NULL, selected = "All"),
        selectInput("country_filter", "Filter by Country",
                    choices = NULL, selected = "All"),
        actionButton("random_recipe", "\U0001F3B2 Pick a Random Recipe")
      ),
      mainPanel(
        h3("Selected Recipe"),
        textOutput("recipe_name"),
        textOutput("recipe_course"),
        textOutput("recipe_style"),
        textOutput("recipe_country"),
        textOutput("recipe_source"),
        textOutput("recipe_notes"),
        uiOutput("recipe_link")
      )
    )
  ),
  
  # -------------------- PAGE 2: CREATIVE --------------------
  tabPanel(
    "Creative Sampler",
    sidebarLayout(
      sidebarPanel(
        selectInput(
          "creative_mode",
          "Creative Mode",
          choices = c(
            "Random Image (Default)",
            "Random Unsplash Image",
            "Random Creative Idea",
            "Random Pantone Color"
          )
        ),
        actionButton("random_creative", "\U2728 Surprise Me")
      ),
      
      mainPanel(
        uiOutput("creative_output")
      )
    )
  )
)

## file: server.R
library(shiny)
library(openxlsx2)
library(dplyr)

server <- function(input, output, session) {
  
  # -------------------- LOAD DATA --------------------
  # In Shinylive, files must be fetched over HTTP into the Wasm virtual filesystem
  download.file(
  "https://raw.githubusercontent.com/taniawyss/oziblue/main/oziblue/rolodex/data/liste_recettes.xlsx",
  "liste_recettes.xlsx"
)
download.file(
  "https://raw.githubusercontent.com/taniawyss/oziblue/main/oziblue/rolodex/data/creative_ideas.xlsx",
  "creative_ideas.xlsx"
)
  recipes <- read_xlsx("liste_recettes.xlsx")
  ideas   <- read_xlsx("creative_ideas.xlsx")
  
  # -------------------- FILTERS --------------------
  updateSelectInput(session, "course_filter",
                    choices = c("All", sort(unique(recipes$Course))))
  updateSelectInput(session, "country_filter",
                    choices = c("All", sort(unique(recipes$Country))))
  
  filtered_recipes <- reactive({
    df <- recipes
    if (input$course_filter != "All")
      df <- df %>% filter(Course == input$course_filter)
    if (input$country_filter != "All")
      df <- df %>% filter(Country == input$country_filter)
    df
  })
  
  selected_recipe <- eventReactive(input$random_recipe, {
    filtered_recipes() %>% slice_sample(n = 1)
  })
  
  output$recipe_name    <- renderText(paste("Recipe:", selected_recipe()$Recettes))
  output$recipe_course  <- renderText(paste("Course:", selected_recipe()$Course))
  output$recipe_style   <- renderText(paste("Style:",  selected_recipe()$Style))
  output$recipe_country <- renderText(paste("Country:", selected_recipe()$Country))
  output$recipe_source  <- renderText(paste("Source:", selected_recipe()$Source))
  output$recipe_notes   <- renderText({
    notes <- selected_recipe()$Notes
    if (!is.na(notes) && nzchar(notes)) paste("Notes:", notes)
  })
  
  output$recipe_link <- renderUI({
    url <- selected_recipe()$Link
    if (!is.na(url) && nzchar(url)) {
      tags$a(href = url, url, target = "_blank")
    }
  })
  
  # -------------------- IMAGE SAMPLING --------------------
  # In Shinylive, list.files() cannot scan the filesystem.
  # Images are served as static URLs — hardcode the list here.
  # Add or remove filenames if your www/images/ folder changes.
  get_image <- reactive({
  c(
    "https://raw.githubusercontent.com/taniawyss/oziblue/main/oziblue/rolodex/www/images/016.JPG",
    "https://raw.githubusercontent.com/taniawyss/oziblue/main/oziblue/rolodex/www/images/Hand-Colored-Engraving-Of-A-Peony.jpg",
    "https://raw.githubusercontent.com/taniawyss/oziblue/main/oziblue/rolodex/www/images/butterflies_merian.png"
  )
})
  
  # -------------------- CREATIVE OUTPUT --------------------
  output$creative_output <- renderUI({
    req(input$random_creative)
    
    mode <- input$creative_mode
    
    if (mode == "Random Image (Default)") {
      
      imgs <- get_image()
      img  <- sample(imgs, 1)
      
      # Images are served as static URLs — use src directly, no base64 encoding needed
      tagList(
        tags$img(src = img, style = "max-width:500px;"),
        tags$p(strong("File:"), basename(img))
      )
      
} else if (mode == "Random Unsplash Image") {
  
  unsplash_key <- "9JmLUmuslmpYpBBjZRbg1Nn7FFGY052ySt8XqSS_wtg"
  
  url <- paste0(
    "https://api.unsplash.com/photos/random",
    "?orientation=landscape",
    "&client_id=", unsplash_key
  )
  
  result <- tryCatch({
    con <- url(url)
    on.exit(close(con))
    jsonlite::fromJSON(readLines(con, warn = FALSE))
  }, error = function(e) NULL)
  
  if (is.null(result)) {
    p("Could not load image. Please try again.")
  } else {
    img_url    <- result$urls$regular
    author     <- result$user$name
    author_url <- result$user$links$html
    photo_url  <- result$links$html
    
    tagList(
      tags$img(src = img_url, style = "max-width:500px;"),
      tags$p(
        "Photo by ",
        tags$a(href = author_url, author, target = "_blank"),
        " on ",
        tags$a(href = photo_url, "Unsplash", target = "_blank")
      )
    )
  } else if (mode == "Random Creative Idea") {
      
      idea <- ideas %>% slice_sample(n = 1)
      tagList(
        h3(idea$idea),
        p(paste("Type:", idea$type))
      )
      
    } else if (mode == "Random Pantone Color") {
  col <- isolate(rgb(runif(1), runif(1), runif(1)))
  tagList(
    div(style = paste0(
      "width:200px;height:200px;",
      "background-color:", col, ";border-radius:10px;"
    )),
    h4(col)
  )
}
  })
}