From b13d42a3a346cfafd239da81a364cb919c784b2e Mon Sep 17 00:00:00 2001 From: Daylin Morgan Date: Mon, 13 Nov 2023 22:52:01 -0600 Subject: [PATCH] feat: update styles and add random "explore tags" --- src/button.nim | 23 ++++++++++------ src/nimpkgs.nim | 72 ++++++++++++++++++++++++++++++------------------ src/packages.nim | 33 ++++++++++++++++++++-- 3 files changed, 89 insertions(+), 39 deletions(-) diff --git a/src/button.nim b/src/button.nim index c7511ba..42d8e0a 100644 --- a/src/button.nim +++ b/src/button.nim @@ -2,12 +2,17 @@ import std/[dom, sugar] include karax/prelude import karax/vstyles + proc showScrollToTop() = - let mybutton = document.getElementById("myBtn") - if document.body.scrollTop > 500 or document.documentElement.scrollTop > 500: - mybutton.style.display = "block" - else: - mybutton.style.display = "none" + # TODO: only show button when scrolling up + let mybtn = document.getElementById("scrollBtn") + # if document.body.scrollTop > 500 or document.documentElement.scrollTop > 500: + let show = (document.body.scrollTop > 500) or ( + document.documentElement.scrollTop > 500) + mybtn.style.display = + if show: "block" + else: "none" + proc scrollToTop*() = document.body.scrollTop = 0 @@ -20,10 +25,10 @@ proc scrollToTopButton*(): VNode = result = buildHtml(tdiv): button( class = - "absolute fixed md:bottom-10 md:right-10 bottom-2 right-2" & - "md:p-5 p-2 cursor-pointer z-99 rounded" & - "bg-ctp-rosewater hover:bg-ctp-mauve text-ctp-mantle ", - `id` = "myBtn", + " absolute fixed md:bottom-10 md:right-10 bottom-2 right-2 " & + " md:p-5 p-2 cursor-pointer z-99 rounded " & + " bg-ctp-rosewater hover:bg-ctp-mauve text-ctp-mantle ", + `id` = "scrollBtn", onClick = scrollToTop, style = "display:none;".toCss ): diff --git a/src/nimpkgs.nim b/src/nimpkgs.nim index 326e0df..5f51ed3 100644 --- a/src/nimpkgs.nim +++ b/src/nimpkgs.nim @@ -1,9 +1,7 @@ -import std/[jsconsole, strutils, sets, sequtils, random] +import std/[strutils, sets, sequtils, random] include karax / prelude -import karax / vstyles -import packages -import button +import packages, button type Query = object @@ -11,12 +9,14 @@ type randomize() + var filteredPackages: seq[Package] = allPackages searchInput: kstring = "".kstring const packagesGitUrl = "https://github.com/nim-lang/packages/blob/" & packagesHash & "/packages.json" numPackages = allPackages.len + numTags = allTags.len colors = [ "flamingo", "pink", @@ -33,14 +33,20 @@ const "lavender" ] let - accent = colors.sample() + accent = (" " & colors.sample() & " ").kstring textStyle = (" text-ctp-" & accent & " ").kstring borderStyle = (" b-ctp-" & accent & " ").kstring - randomIndices = [ - rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), rand( - numPackages-1), rand(numPackages-1), - rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), rand( - numPackages-1), rand(numPackages-1)] + randomPkgIndices = [ + rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), + rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), + rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), + rand(numPackages-1)] + randomTagIndices = [ + rand(numTags-1), rand(numTags-1), rand(numTags-1), + rand(numTags-1), rand(numTags-1), rand(numTags-1) + ] + + proc parseQuery(s: kstring): Query = result = Query() @@ -95,8 +101,7 @@ proc noProtocol(s: kstring): kstring = kstring(($s).replace("http://", proc toDom(pkg: Package): VNode = result = buildHtml(tdiv(class = "flex flex-col bg-ctp-crust rounded-xl my-5 p-5")): - h2(class = (textStyle & "font-black md:text-2xl text-lg").kstring, - style = "font-variation-settings: 'CASL' 1".toCss): + h2(class = (textStyle & "font-black md:text-2xl text-lg font-casual").kstring): text ("# " & pkg.name).kstring if pkg.alias != "": tdiv: @@ -152,8 +157,13 @@ proc getSearchInput() = searchInput = getVNodeById("search").getInputText searchPackages(parseQuery(searchInput)) +proc render(t: Tag): VNode = + result = buildHtml(tdiv(class = "bg-ctp-mantle m-1 p-1 rounded hover:text-ctp-mauve")): + tdiv(onClick = setSearch("tag:" & t.name)): + text t.name & "|" & kstring($t.packages) + proc searchBar(): Vnode = - result = buildHtml(tdiv(class = "flex flex-col lg:flex-row items-center my-5")): + result = buildHtml(tdiv(class = "flex flex-col md:flex-row md:items-center md:my-5")): tdiv(class = "flex flex-row my-2"): input(`type` = "text", class = "border-1 bg-ctp-crust rounded mx-3 p-2".kstring & borderStyle, `id` = "search", placeholder = "query", value = searchInput, @@ -161,25 +171,33 @@ proc searchBar(): Vnode = button(`type` = "button", class = "border-1 rounded p-2".kstring & borderStyle, onClick = getSearchInput): text "search" - tdiv(class = "text-xs md:mx-5 flex flex-col md:flex-row"): + #[ + tdiv(class = "md:mx-5 flex flex-col items-center"): tdiv: text "examples: " - tdiv: - span(class = "bg-ctp-surfacetwo rounded text-ctp-subtextone p-1 grow-0"): - text "tag:database sqlite | license:MIT javascript" + tdiv(class="flex flex-col"): + for msg in ["tag:database sqlite","license:MIT javascript"]: + span(class = "bg-ctp-mantle rounded text-ctp-subtextone m-1 p-1 text-xs"): + text msg + ]# + tdiv(class = "flex flex-col mx-5"): + tdiv: text "explore tags:" + tdiv(class = "flex flex-wrap text-sm"): + for idx in randomTagIndices: + allTags[idx].render + proc headerBar(): VNode = result = buildHtml(tdiv(class = "mt-5 mx-5 flex flex-wrap")): tdiv(class = "flex items-center my-3 grow"): img(src = "img/logo.svg", class = "inline h-1em md:h-2em px-1") - span(class = "font-bold md:text-4xl text-lg", - style = "font-variation-settings: 'CASL' 1".toCss): + span(class = "font-bold md:text-4xl text-lg font-casual"): text "pkgs" label(`for` = "menu-toggle", - class = "cursor-pointer md:hidden flex items-center px-3 py-2" + class = "cursor-pointer lg:hidden flex items-center px-3 py-2" ): text "menu" input(class = "hidden", type = "checkbox", `id` = "menu-toggle") - tdiv(class = "md:flex md:items-center justify-between hidden w-full md:w-auto", + tdiv(class = "lg:flex lg:items-center justify-between hidden w-full lg:w-auto", `id` = "menu"): nav: ul(class = "md:flex items-center"): @@ -187,8 +205,8 @@ proc headerBar(): VNode = (packagesGitUrl, "nim-lang/packages:" & packagesHashAbbr), ("http://github.com/daylinmorgan/nimpkgs", "source") ]: - li(class = "px-1"): - a(href = url.kstring, class = "text-ctp-surfacetwo text-xs"): + li(class = "p-2 hover:bg-ctp-mantle rounded text-sm"): + a(href = url.kstring, class = accent): text msg proc includedLinks(pkgs: seq[Package]): HashSet[char] = @@ -196,9 +214,9 @@ proc includedLinks(pkgs: seq[Package]): HashSet[char] = proc letterlink(): VNode = let activeLinks = includedLinks(filteredPackages) - result = buildHtml(tdiv(class = "flex flex-wrap md:text-xl text-md space-x-4 capitalize")): + result = buildHtml(tdiv(class = "flex flex-wrap md:text-xl text-lg capitalize w-full justify-evenly gap-x-2 md:gap-x-auto")): for l in LowercaseLetters: - tdiv: + tdiv(class = "w-5"): if l in activeLinks: a(href = "#" & ($l).kstring): text $l @@ -215,7 +233,7 @@ proc filteredPackagesDom(): VNode = proc createDom(): VNode = - result = buildHtml(tdiv(class = "sm:w-3/4 md:w-2/3 max-w-[95%] md:mx-auto mx-5 md:text-lg text-sm")): + result = buildHtml(tdiv(class = "md:w-3/4 max-w-[95%] md:mx-auto mx-5 md:text-lg text-sm")): headerBar() searchBar() letterlink() @@ -223,7 +241,7 @@ proc createDom(): VNode = text ($filteredPackages.len & "/" & $allPackages.len) & " packages" if searchInput == "": tdiv(): - for idx in randomIndices: + for idx in randomPkgIndices: allPackages[idx].toDom hr() filteredPackagesDom() diff --git a/src/packages.nim b/src/packages.nim index 25017b6..e6a2e1f 100644 --- a/src/packages.nim +++ b/src/packages.nim @@ -1,5 +1,4 @@ -import std/[algorithm, strutils] - +import std/[algorithm, strutils, tables] import karax/kbase import jsony @@ -8,6 +7,9 @@ type Package* = object name*, url*, `method`*, description*, license*, web*, doc*, alias*: kstring tags*: seq[kstring] + Tag* = object + name*: kstring + packages*: int proc parseHook*(s: string, i: var int, v: var kstring) = var str: string @@ -22,8 +24,33 @@ proc getPackages(): seq[Package] = result = packagesJsonStr.fromJson(seq[Package]) result.sort(cmpPkgs) + +#[ +import strutils, tables, heapqueue, algorithm +iterator topN[T](h: CountTable[T]|Table[T, int], n=10): + tuple[cnt: int; key: T] = + var q = initHeapQueue[tuple[cnt: int; key: T]]() + for key, cnt in h: + if q.len < n: + q.push((cnt, key)) + elif cnt > q[0].cnt: # retain 1st seen on tied cnt + discard q.replace((cnt, key)) + while q.len > 0: # q now has top n entries + yield q.pop +]# + +proc getTags(pkgs: seq[Package]): seq[Tag] = + const minPackageCutoff = 10 + var tags: seq[kstring] + for pkg in pkgs: + for tag in pkg.tags: + tags.add tag + for key, cnt in tags.toCountTable: + if cnt > minPackageCutoff: + result.add Tag(name: key, packages: cnt) + const packagesHash* {.strdefine.} = "master" packagesHashAbbr* {.strdefine.} = "master" allPackages* = getPackages() - + allTags* = allPackages.getTags()