Skip to content

Commit

Permalink
feat: implement search engine
Browse files Browse the repository at this point in the history
Signed-off-by: Guillaume Hivert <hivert.is.coming@gmail.com>
  • Loading branch information
ghivert committed May 7, 2024
1 parent 1f8bf0c commit 119e7bf
Show file tree
Hide file tree
Showing 15 changed files with 2,456 additions and 2,338 deletions.
1 change: 0 additions & 1 deletion apps/frontend/gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ plinth = ">= 0.2.0 and < 1.0.0"
sketch = ">= 2.2.0 and < 3.0.0"
tardis = ">= 0.1.0 and < 1.0.0"
gleam_json = ">= 1.0.1 and < 2.0.0"
jot = ">= 0.5.0 and < 1.0.0"

[dev-dependencies]
gleeunit = "~> 1.0"
2 changes: 0 additions & 2 deletions apps/frontend/manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ packages = [
{ name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" },
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
{ name = "grille_pain", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_stdlib", "lustre", "scheduler", "sketch", "tardis"], source = "local", path = "../../packages/grille_pain" },
{ name = "jot", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "F9B974EEB4D687C29A86A41F0384D72EEADCA1D3CF3AF28FEE3135874AE1E93B" },
{ name = "lustre", version = "4.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "258F876CD7AB12C2C773F1A30F76DFC0A0ED989B720070DF32FC0717A6A0E60C" },
{ name = "lustre_http", version = "0.5.2", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_http", source = "hex", outer_checksum = "FB0478CBFA6B16DBE8ECA326DAE2EC15645E04900595EF2C4F039ABFA0512ABA" },
{ name = "plinth", version = "0.2.0", build_tools = ["gleam"], requirements = ["gleam_javascript", "gleam_json", "gleam_stdlib"], otp_app = "plinth", source = "hex", outer_checksum = "83211E672D83F3CE14681D0ECD3AD883EE7588E423E7C9DDDB460014AD60AC24" },
Expand All @@ -29,7 +28,6 @@ gleam_json = { version = ">= 1.0.1 and < 2.0.0" }
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
gleeunit = { version = "~> 1.0" }
grille_pain = { path = "../../packages/grille_pain" }
jot = { version = ">= 0.5.0 and < 1.0.0"}
lustre = { version = ">= 4.2.0 and < 5.0.0" }
lustre_http = { version = "~> 0.5" }
plinth = { version = ">= 0.2.0 and < 1.0.0" }
Expand Down
3 changes: 2 additions & 1 deletion apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"preview": "vite preview"
},
"dependencies": {
"firebase": "^10.10.0"
"firebase": "^10.10.0",
"showdown": "^2.1.0"
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
Expand Down
3 changes: 2 additions & 1 deletion apps/frontend/src/data/decoders/signature.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gleam/dynamic
import gleam/int
import gleam/io
import gleam/list
import gleam/option.{type Option}
import gleam/result
Expand Down Expand Up @@ -172,7 +173,7 @@ fn decode_type_alias(dyn) {
TypeAlias(width, a, b)
},
dynamic.field("parameters", dynamic.int),
dynamic.field("type", decode_type),
dynamic.field("alias", decode_type),
)(dyn)
}

Expand Down
4 changes: 4 additions & 0 deletions apps/frontend/src/data/model.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ pub fn update_input(model: Model, content: String) {
pub fn update_search_results(model: Model, search_results: List(SearchResult)) {
Model(..model, search_results: search_results)
}

pub fn reset(_model: Model) {
Model(search_results: [], input: "")
}
4,634 changes: 2,317 additions & 2,317 deletions apps/frontend/src/data/model/mock.gleam

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions apps/frontend/src/data/msg.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ pub type Msg {
SubmitSearch
SearchResults(Result(List(SearchResult), http.HttpError))
UpdateInput(String)
Reset
}
4 changes: 4 additions & 0 deletions apps/frontend/src/frontend.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ fn update(model: Model, msg: Msg) {
|> http.get("http://localhost:3000/search?q=" <> model.input, _)
|> pair.new(model, _)
}
msg.Reset ->
model
|> model.reset()
|> update.none()
msg.SearchResults(search_results) -> {
let toast =
search_results
Expand Down
16 changes: 16 additions & 0 deletions apps/frontend/src/frontend/documentation.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import frontend/documentation/styles as s
import gleam/io
import gleam/list
import lustre/attribute as a
import lustre/element
import lustre/element/html as h

@external(javascript, "../markdown.ffi.mjs", "convert")
fn converter(content: String) -> String

pub fn view(document: String) {
let content =
document
|> converter()
h.div([a.attribute("dangerous-unescaped-html", content)], [])
}
7 changes: 7 additions & 0 deletions apps/frontend/src/frontend/documentation/styles.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sketch as s

pub fn paragraph() {
s.class([s.white_space("pre-wrap")])
|> s.memo()
|> s.to_lustre()
}
54 changes: 50 additions & 4 deletions apps/frontend/src/frontend/styles.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,34 @@ pub fn navbar() {
s.position("sticky"),
s.top(px(0)),
s.display("flex"),
s.align_items("baseline"),
s.justify_content("end"),
s.align_items("center"),
s.justify_content("space-between"),
s.grid_area("navbar"),
s.padding_left(px(48)),
s.gap(px(48)),
s.background(palette.dark.underwater_blue),
])
|> s.memo()
|> s.to_lustre()
}

pub fn nav_links() {
s.class([
s.display("flex"),
s.align_items("baseline"),
s.gap(px(48)),
s.padding(px(48)),
])
|> s.memo()
|> s.to_lustre()
}

pub fn navbar_search() {
s.class([
s.display("flex"),
s.gap(px(48)),
s.align_items("center"),
s.flex("1"),
])
|> s.memo()
|> s.to_lustre()
Expand All @@ -48,6 +71,7 @@ pub fn trending() {
s.gap(px(3)),
s.align_items("end"),
s.color(palette.dark.dark_white),
s.white_space("nowrap"),
])
|> s.memo()
|> s.to_lustre()
Expand Down Expand Up @@ -85,15 +109,30 @@ pub fn main_wrapper() {
|> s.to_lustre()
}

pub fn search_title() {
pub fn navbar_search_title() {
s.class([
s.font_size(size.rem_(1.2)),
s.compose(search_title_()),
s.text_decoration("none"),
s.cursor("pointer"),
])
|> s.memo()
|> s.to_lustre()
}

pub fn search_title_() {
s.class([
s.font_family("Lexend"),
s.display("flex"),
s.align_items("center"),
s.gap(px(12)),
s.font_size(size.rem_(2.5)),
s.color(palette.dark.white),
])
}

pub fn search_title() {
s.class([s.compose(search_title_()), s.font_size(size.rem_(2.5))])
search_title_()
|> s.memo()
|> s.to_lustre()
}
Expand Down Expand Up @@ -125,11 +164,18 @@ pub fn search_input() {
s.color(palette.dark.charcoal),
s.active([s.outline("2px solid " <> palette.dark.faff_pink)]),
s.focus([s.outline("2px solid " <> palette.dark.faff_pink)]),
s.width(size.percent(100)),
])
|> s.memo()
|> s.to_lustre()
}

pub fn search_input_wrapper() {
s.class([s.width_("100%")])
|> s.memo()
|> s.to_lustre()
}

pub fn search_submit() {
s.class([
s.grid_area("submit"),
Expand Down
42 changes: 31 additions & 11 deletions apps/frontend/src/frontend/view.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import data/decoders/search_result
import data/decoders/signature.{type Parameter, type Type, Parameter}
import data/model.{type Model}
import data/msg
import frontend/documentation
import frontend/footer/view as footer
import frontend/styles as s
import frontend/types as t
import gleam/bool
import gleam/int
import gleam/io
import gleam/list
import gleam/option.{None, Some}
import gleam/string
Expand All @@ -28,15 +28,35 @@ pub fn idt(indent: Int) {
pub const gloogle_description = "Gloogle can search through all public gleam packages, to help you find the function you're looking for! Enter a type or a function name to get some results."

pub fn view(model: Model) {
h.div([s.layout()], [navbar(), body(model), footer.view()])
h.div([s.layout()], [navbar(model), body(model), footer.view()])
}

fn navbar() {
fn navbar(model: Model) {
h.div([s.navbar()], [
h.div([], [h.text("Packages")]),
h.div([s.trending()], [
h.text("Trending"),
h.span([s.coming_soon()], [h.text(" (coming soon…)")]),
case model.search_results {
[] -> h.div([], [])
_ ->
h.div([s.navbar_search()], [
h.a([s.navbar_search_title(), e.on_click(msg.Reset)], [
h.img([a.src("/images/lucy.svg"), s.search_lucy()]),
h.text("Gloogle"),
]),
h.form([s.search_input_wrapper(), e.on_submit(msg.SubmitSearch)], [
h.input([
s.search_input(),
a.placeholder("Search for a function, or a type"),
e.on_input(msg.UpdateInput),
a.value(model.input),
]),
]),
])
},
h.div([s.nav_links()], [
h.div([], [h.text("Packages")]),
h.div([s.trending()], [
h.text("Trending"),
h.span([s.coming_soon()], [h.text(" (coming soon…)")]),
]),
]),
])
}
Expand Down Expand Up @@ -302,13 +322,13 @@ fn view_search_results(search_results: List(search_result.SearchResult)) {
]),
h.div([s.search_body()], [
h.code([s.signature()], view_signature(item)),
case item.documentation == "" {
False ->
case item.documentation {
"" -> element.none()
_ ->
h.div([s.documentation()], [
h.div([s.documentation_title()], [h.text("Documentation")]),
h.text(item.documentation),
documentation.view(item.documentation),
])
True -> element.none()
},
]),
])
Expand Down
8 changes: 8 additions & 0 deletions apps/frontend/src/markdown.ffi.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import showdown from 'showdown'

export function convert(content) {
const converter = new showdown.Converter({
tasklists: true,
})
return converter.makeHtml(content)
}
3 changes: 2 additions & 1 deletion apps/frontend/src/toast/error.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gleam/dynamic
import gleam/int
import gleam/io
import gleam/json
import gleam/list
import gleam/option.{Some}
Expand Down Expand Up @@ -36,7 +37,7 @@ pub fn describe_json_error(error: json.DecodeError) {
}

pub fn describe_http_error(error: http.HttpError) {
case error {
case io.debug(error) {
http.BadUrl(url) -> Some("Bad URL: " <> url)
http.InternalServerError(error) ->
Some({ "Internal server error. Please try again later. " <> error })
Expand Down
12 changes: 12 additions & 0 deletions apps/frontend/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,11 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==

commander@^9.0.0:
version "9.5.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==

debug@^4.1.0:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
Expand Down Expand Up @@ -1260,6 +1265,13 @@ safe-buffer@>=5.1.0:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==

showdown@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5"
integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==
dependencies:
commander "^9.0.0"

source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
Expand Down

0 comments on commit 119e7bf

Please sign in to comment.