Skip to content
This repository was archived by the owner on Feb 15, 2022. It is now read-only.

Added World Map to Academic Excellence Page #513

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
},
"dependencies": {
"bs-platform": "^9.0.2",
"leaflet": "^1.7.1",
"next": "^11.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2"
"react-dom": "^17.0.2",
"react-leaflet": "^3.2.0"
},
"dependenciesDescription": {
"bs-platform": "This a regular dependency because the included standard libraries are used during runtime"
Expand Down
54 changes: 36 additions & 18 deletions pages/[lang]/principles/academic.res
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
open! Import

module Link = Next.Link

module T = {
type t = {acads: array<Ood.Academic_institution.t>}

let s = React.string
include Jsonable.Unsafe
//PageBasicDetail Module
let map: React.component<{
"props": Map.props,
}> = Next.Dynamic.dynamic(
() => Next.Dynamic.import_("../../../src/Map.js"),
Next.Dynamic.options(~ssr=false, ~loading=() => <p> {s("loading...")} </p>, ()),
)
module PageBasic = {
@react.component
let make = (~lang) => <>
Expand Down Expand Up @@ -127,31 +134,42 @@ module T = {
</>
}
}
//TODO: Implement Map
module Map = {
@react.component
let make = (~marginBottom=?) => <>
<SectionContainer.MediumCentered ?marginBottom paddingX="px-12">
<h2 className="mb-16 text-grey-900 text-3xl mb-5 lg:text-4xl font-bold text-center">
{s("Ocaml Courses around the World")}
</h2>
</SectionContainer.MediumCentered>
<SectionContainer.ResponsiveCentered ?marginBottom>
// TODO: try switching to a grid
<div className="bg-white flex flex-wrap justify-center lg:justify-between ">
<img src={`/static/worldmap.jpg`} alt="" />
</div>
</SectionContainer.ResponsiveCentered>
</>
}

module Params = Pages.Params.Lang

@react.component
let make = (~content, ~params as {Params.lang: lang}) => <>
<PageBasic lang />
<University marginBottom={Tailwind.Breakpoint.make(#mb10, ~lg=#mb32, ())} content />
<Map marginBottom={Tailwind.Breakpoint.make(#mb10, ~lg=#mb32, ())} />
{React.createElement(
map,
Map.makeProps(
~props={
"marginBottom": Some({Tailwind.Breakpoint.make(#mb10, ~lg=#mb32, ())}),
"zoom": 0.5,
"center": {
LatLng.lat: 0.0,
lng: 0.0,
},
"position": content.acads,
"maxBound": {
LatLng.mib: {
lat: 85.0511,
lng: -180.0,
},
LatLng.mab: {
lat: -85.0511,
lng: 180.0,
},
},
"minZoom": 1.9,
"scrollWheelZoom": true,
"attribution": "<a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors",
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
},
(),
),
)}
</>

let contentEn = {
Expand Down
3 changes: 2 additions & 1 deletion pages/[lang]/principles/academic.resi
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
type t = {acads: array<Ood.Academic_institution.t>}
type t = {acads: array<Ood.Academic_institution.t>
}

include Pages.S with type t := t
Binary file added public/static/marker-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/LatLng.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type t = {
lat: float,
lng: float,
}
type bound = {
mib: t,
mab: t,
}
8 changes: 8 additions & 0 deletions src/LatLng.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type t = {
lat: float,
lng: float,
}
type bound = {
mib: t,
mab: t,
}
89 changes: 89 additions & 0 deletions src/Map.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
let s = React.string
module MapContainer = Mapbinding.MapContainer
module TileLayer = Mapbinding.TileLayer
module Popup = Mapbinding.Popup
module Marker = Mapbinding.Marker

//TODO: Implement Map
module MarkArray = {
type t = {
positions: LatLng.t,
name: string,
}
}

type props = {
"marginBottom": option<Tailwind.Breakpoint.t<Tailwind.Margin.Bottom.t>>,
"zoom": float,
"minZoom": float,
"center": LatLng.t,
"position": array<Ood.Academic_institution.t>,
"scrollWheelZoom": bool,
"attribution": string,
"url": string,
"maxBound": LatLng.bound,
}
@react.component
let make = (~props: props) => {
let marginBottom = props["marginBottom"]
let zoom = props["zoom"]
let center = props["center"]
let acads = props["position"]
let minZoom = props["minZoom"]
let attribution = props["attribution"]
let url = props["url"]
let maxBound = props["maxBound"]
let scrollWheelZoom = props["scrollWheelZoom"]
let options = {
Mapbinding.iconUrl: "/static/marker-icon.png",
iconSize: {
x: 25.0,
y: 46.0,
},
iconAnchor: {
x: 13.0,
y: 46.0,
},
}
let icon = Mapbinding.icon(Mapbinding.leaflet, ~options)
let p = acads->Belt.Array.map((c: Ood.Academic_institution.t) => {
MarkArray.name: c.Ood.Academic_institution.name,
MarkArray.positions: {
LatLng.lat: switch c.Ood.Academic_institution.location {
| None => 0.0
| Some(location) => location.lat
},
lng: switch c.Ood.Academic_institution.location {
| None => 0.0
| Some(location) => location.long
},
},
})

<>
<SectionContainer.MediumCentered ?marginBottom paddingX="px-12">
<h2 className="mb-16 text-grey-900 text-3xl mb-5 lg:text-4xl font-bold text-center">
{s("Ocaml Courses around the World")}
</h2>
</SectionContainer.MediumCentered>
<SectionContainer.ResponsiveCentered ?marginBottom>
// TODO: try switching to a grid
<div className="bg-white flex-wrap justify-center lg:justify-between m-8 ">
// <img src={`/static/worldmap.jpg`} alt="" />
<MapContainer center zoom scrollWheelZoom maxBounds=maxBound minZoom id="mapid">
<TileLayer attribution url noWrap=true />
{p
|> Array.mapi((idx, c) =>
<Marker position=c.MarkArray.positions icon>
<Popup className="h-16 font-bold text-xl italic font-serif text-center ">
{React.string(c.name)}
</Popup>
</Marker>
)
|> React.array}
</MapContainer>
</div>
</SectionContainer.ResponsiveCentered>
</>
}
let default = make
21 changes: 21 additions & 0 deletions src/Map.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
module MarkArray: {
type t = {
positions: LatLng.t,
name: string,
}
}
type props = {
"marginBottom": option<Tailwind.Breakpoint.t<Tailwind.Margin.Bottom.t>>,
"zoom": float,
"minZoom": float,
"center": LatLng.t,
"position": array<Ood.Academic_institution.t>,
"scrollWheelZoom": bool,
"attribution": string,
"url": string,
"maxBound": LatLng.bound,
}

@react.component
let make: (~props: props) => React.element
let default: {"props": props} => React.element
56 changes: 56 additions & 0 deletions src/Mapbinding.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module MapContainer = {
@module("react-leaflet") @react.component
external make: (
~className: string=?,
~center: LatLng.t,
~zoom: float,
~zoomControl: bool=?,
~scrollWheelZoom: bool,
~id: string=?,
~minZoom: float,
~maxBounds: LatLng.bound,
~children: React.element,
) => React.element = "MapContainer"
}
module TileLayer = {
@module("react-leaflet") @react.component
external make: (~attribution: string=?, ~noWrap: bool, ~url: string) => React.element =
"TileLayer"
}
//Abstract Icon type
type icon

type iconOptions = {iconUrl: string, iconSize: Point.t, iconAnchor: Point.t}

// Abstract Leaflet Object type
type leaflet

// Binding to the Leaflet function `icon` which creates an Icon object
@send external icon: (leaflet, ~options: iconOptions) => icon = "icon"
@val external leaflet: leaflet = "L"

module Marker = {
@module("react-leaflet") @react.component
external make: (~position: LatLng.t, ~icon: icon=?, ~children: React.element=?) => React.element =
"Marker"
}

module Popup = {
@module("react-leaflet") @react.component
external make: (
~maxWidth: int=?,
~minWidth: int=?,
~maxHeight: int=?,
~autoPan: bool=?,
~autoPanPaddingTopLeft: Point.t=?,
~autoPanPaddingBottomRight: Point.t=?,
~autoPanPadding: Point.t=?,
~keepInView: bool=?,
~closeButton: bool=?,
~autoClose: bool=?,
~closeOnEscapeKey: bool=?,
~closeOnClick: bool=?,
~className: string=?,
~children: React.element=?,
) => React.element = "Popup"
}
54 changes: 54 additions & 0 deletions src/Mapbinding.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module MapContainer: {
@react.component
let make: (
~className: string=?,
~center: LatLng.t,
~zoom: float,
~zoomControl: bool=?,
~scrollWheelZoom: bool,
~id: string=?,
~minZoom: float,
~maxBounds: LatLng.bound,
~children: React.element,
) => React.element
}
module TileLayer: {
@react.component
let make: (~attribution: string=?, ~noWrap: bool, ~url: string) => React.element
}
//Abstract Icon type
type icon

type iconOptions = {iconUrl: string, iconSize: Point.t, iconAnchor: Point.t}

// Abstract Leaflet Object type
type leaflet

// Binding to the Leaflet function `icon` which creates an Icon object
@send external icon: (leaflet, ~options: iconOptions) => icon = "icon"
@val external leaflet: leaflet = "L"

module Marker: {
@react.component
let make: (~position: LatLng.t, ~icon: icon=?, ~children: React.element=?) => React.element
}

module Popup: {
@react.component
let make: (
~maxWidth: int=?,
~minWidth: int=?,
~maxHeight: int=?,
~autoPan: bool=?,
~autoPanPaddingTopLeft: Point.t=?,
~autoPanPaddingBottomRight: Point.t=?,
~autoPanPadding: Point.t=?,
~keepInView: bool=?,
~closeButton: bool=?,
~autoClose: bool=?,
~closeOnEscapeKey: bool=?,
~closeOnClick: bool=?,
~className: string=?,
~children: React.element=?,
) => React.element
}
15 changes: 15 additions & 0 deletions src/Next.res
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,18 @@ module Head = {
@module("next/head") @react.component
external make: (~children: React.element) => React.element = "default"
}

module Dynamic = {
@deriving(abstract)
type options = {
@optional
ssr: bool,
@optional
loading: unit => React.element,
}

@module("next/dynamic")
external dynamic: (unit => Js.Promise.t<'a>, options) => 'a = "default"

@val external import_: string => Js.Promise.t<'a> = "import"
}
14 changes: 14 additions & 0 deletions src/Next.resi
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,17 @@ module Head: {
@react.component
let make: (~children: React.element) => React.element
}
module Dynamic: {
@deriving(abstract)
type options = {
@optional
ssr: bool,
@optional
loading: unit => React.element,
}

@module("next/dynamic")
external dynamic: (unit => Js.Promise.t<'a>, options) => 'a = "default"

@val external import_: string => Js.Promise.t<'a> = "import"
}
4 changes: 4 additions & 0 deletions src/Point.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type t = {
x: float,
y: float,
}
4 changes: 4 additions & 0 deletions src/Point.resi
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type t = {
x: float,
y: float,
}
Loading