Generates a responsive timeline of F# meetups around the world
#r @"packages/FSharp.Data/lib/net40/FSharp.Data.dll" | |
#load "FsHtml.fs" // "paket-files/ptrelford/FsHtml/src/FsHtml.fs" | |
open System | |
open FSharp.Data | |
open FsHtml | |
type Events = JsonProvider<"https://api.meetup.com/fsharplondon/events?&sign=true&photo-host=public&page=200&status=past,upcoming"> | |
let meetups = [ | |
"fsharplondon";"FSharpBristol";"Cambridge-F-Community";"F-Coventry" | |
"fsharpsydney";"Auckland-F-Programming-Meetup";"FSharpKorea" | |
"Gauteng-F-Programming-Meetup";"FSharp-Toronto"; | |
"Chennai-F-User-Group";"Bangalore-fsharp-Programming-Meetup" | |
"MoedegruppeFunktionelleKoebenhavnere";"OsloFSharp";"FSharpHelsinki" | |
"zurich-fsharp-users";"Functional-Programming-in-F";"fsharp-toulouse" | |
"F-un-and-More-Rhein-Main";"FSharp-Vienna";"fsharpminsk";"Kyiv-FSharp-Group" | |
"Athens-FSharp";"FSharp-Italia";"FSharp-Milano" | |
"madrid-fsharp";"FSharp-Barcelona" | |
"FSharp-Bogota";"F-Programming-User-Group-Oaxaca" | |
"Chicago-F-Users";"Dallas-F-User-Group";"Houston-FSharp-User-Group" | |
"Austin-F-Meetup";"nashfsharp";"IndianapolisFSharpDevelopers" | |
"slc-fsharp";"Columbus-F-Sharp-User-Group" | |
"sfsharp"; "Silicon-Valley-FSharp"; "Portland-F-Meetup-Group";"FSharpSeattle" | |
"nyc-fsharp";"DC-fsharp";"Detroit-F-Meetup";"Philly-FSharp"; | |
"New-England-F-Users-Group" | |
] | |
type Event<'a> = { | |
StartTime : DateTime | |
Link : string | |
Title : string | |
Summary : string | |
Location : string | |
Venue : 'a | |
} | |
let events = | |
[|for meetup in meetups |> Seq.distinct do | |
let events = Events.Load(sprintf "https://api.meetup.com/%s/events?&sign=true&photo-host=public&page=200&status=past,upcoming" meetup) | |
for event in events -> | |
let epoch = System.DateTime(1970,1,1) | |
let startTime = epoch.AddMilliseconds(float event.Time + float event.UtcOffset) | |
let city = | |
match event.Venue with | |
| Some venue -> venue.City | |
| None -> event.Group.Name | |
{ StartTime=startTime; Link=event.Link; Title=event.Name; Summary=event.Description; Location=city; Venue=event.Venue} | |
|] | |
|> Array.where (fun x -> x.StartTime < DateTime.Now.AddMonths(1)) | |
|> Array.sortByDescending (fun x -> x.StartTime) | |
let blocks = [ | |
for event in events -> | |
div [ | |
"itemscope"%="" | |
"itemtype"%="http://schema.org/Event" | |
"class"%="cd-timeline-block" | |
// Location | |
a [ | |
yield! ["itemprop"%="location";"itemscope"%="";"itemtype"%="https://schema.org/Place"] | |
yield "target"%="_blank" | |
match event.Venue with | |
| Some venue -> | |
yield "href"%=(sprintf "https://www.google.com/maps/@%M,%M,8z" venue.Lat venue.Lon) | |
//yield "href"%=(sprintf "https://www.google.com/maps/?q=%M,%M" venue.Lat venue.Lon) // with pin | |
yield "title"%=(venue.Name+", "+venue.City) | |
| None -> | |
yield "href"%=event.Link | |
yield div [ | |
yield "class"%="cd-timeline-img" | |
yield img ["src"%="img/cd-icon-location.svg"] | |
] | |
// Location name | |
match event.Venue with | |
| Some venue -> | |
yield meta ["itemprop"%="name";"content"%=venue.Name] | |
| None -> | |
yield meta ["itemprop"%="name";"content"%=event.Location] | |
// Postal Adress | |
yield span [ | |
yield! ["itemprop"%="address";"itemscope"%="";"itemtype"%="https://schema.org/PostalAddress"] | |
match event.Venue with | |
| Some venue -> | |
yield meta ["itemprop"%="addressLocality";"content"%=venue.City] | |
yield meta ["itemprop"%="addressCountry";"content"%=venue.Country.ToUpper()] | |
| None -> | |
yield meta ["itemprop"%="name";"content"%=event.Location] | |
] | |
] | |
// Content | |
div [ | |
"class"%="cd-timeline-content" | |
div [ | |
h2 %event.Location | |
] | |
br [] | |
a [ | |
"itemprop"%="url"; | |
"href"%=(event.Link); | |
span ["itemprop"%="name";Text event.Title] | |
] | |
br [] | |
span [ | |
"itemprop"%="startDate" | |
"class"%="cd-date" | |
Text (event.StartTime.ToString("D")) | |
] | |
] | |
] | |
] | |
let timeline = section ("id"%="cd-timeline"::"class"%="cd-container"::blocks) | |
// Based on CodyHouse Vertical Timeline sample: https://codyhouse.co/gem/vertical-timeline/ | |
let html = | |
"""<!doctype html> | |
<html lang="en" class="no-js"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link href='http://fonts.googleapis.com/css?family=Droid+Serif|Open+Sans:400,700' rel='stylesheet' type='text/css'> | |
<link rel="stylesheet" href="css/reset.css"> <!-- CSS reset --> | |
<link rel="stylesheet" href="css/style.css"> <!-- Resource style --> | |
<script src="js/modernizr.js"></script> <!-- Modernizr --> | |
<title>F# Meetup Timeline</title> | |
</head> | |
<body> | |
<header> | |
<h1>F# Meetup Timeline</h1> | |
</header> | |
{timeline} | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> | |
<script src="js/main.js"></script> <!-- Resource jQuery --> | |
</body> | |
</html>""".Replace("{timeline}", timeline.ToString()) | |
open System.IO | |
let path = Path.Combine(__SOURCE_DIRECTORY__,@"vertical-timeline\vertical-timeline\index.html") | |
System.IO.File.WriteAllText(path, html) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment