Skip to content

Commit

Permalink
feat: ui overhaul
Browse files Browse the repository at this point in the history
- fcio styling
- package search
    - pretty print licenses
    - readable name + link to url
    - list packages' homepage
  • Loading branch information
PhilTaken committed Mar 14, 2024
1 parent f3e2255 commit 7b159d6
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 137 deletions.
3 changes: 3 additions & 0 deletions nix/eval.nix
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
# paths = builtins.listToAttrs ( map (output: {name = output; value = drv.${output};}) drv.outputs );
default_output = drv.outputName;
}
// lib.optionalAttrs (drv ? meta.homepage) {
inherit (drv.meta) homepage;
}
// lib.optionalAttrs (drv ? meta.description) {
inherit (drv.meta) description;
}
Expand Down
2 changes: 1 addition & 1 deletion src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use itertools::Itertools;
use tracing::{debug, info};

use fc_search::{
get_fcio_flake_uris, nix::NixPackage, search::ChannelSearcher, Flake, NaiveNixosOption,
get_fcio_flake_uris, nix::NixPackage, search::ChannelSearcher, Flake, NaiveNixosOption, NixHtml,
};

use serde::Deserialize;
Expand Down
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ pub trait NixHtml {
fn as_html(&self) -> Html;
}

impl<T: NixHtml> NixHtml for Option<T> {
fn as_html(&self) -> Html {
match self {
Some(s) => s.as_html(),
None => Html("".to_string()),
}
}
}

#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
pub struct Html(pub String);

Expand Down
96 changes: 72 additions & 24 deletions src/nix.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use itertools::Itertools;
use rust_embed::RustEmbed;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
Expand All @@ -8,7 +9,7 @@ use std::process::Command;
use tracing::{debug, error};
use url::Url;

use crate::{option_to_naive, Flake, NaiveNixosOption};
use crate::{option_to_naive, Flake, NaiveNixosOption, NixHtml};

#[derive(Deserialize, Debug, Serialize, Clone)]
pub enum ExpressionType {
Expand Down Expand Up @@ -38,38 +39,82 @@ pub struct NixosOption {
pub option_type: String,
}

#[derive(Deserialize, Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct License {
pub free: Option<bool>,
pub full_name: Option<String>,
pub redistributable: Option<bool>,
pub short_name: Option<String>,
pub spdx_id: Option<String>,
pub url: Option<Url>,
}

#[derive(Deserialize, Debug, Serialize, Clone)]
#[derive(Deserialize, Debug, Serialize, Clone, PartialEq, Eq, Hash)]
#[serde(untagged)]
pub enum LicenseT {
pub enum License {
Verbatim(String),
Informative(License),
#[serde(rename_all = "camelCase")]
Informative {
free: Option<bool>,
full_name: Option<String>,
redistributable: Option<bool>,
short_name: Option<String>,
spdx_id: Option<String>,
url: Option<Url>,
},
}

#[derive(Deserialize, Debug, Serialize, Clone)]
impl NixHtml for License {
fn as_html(&self) -> crate::Html {
match self {
Self::Verbatim(s) => crate::Html(format!("<p>{s}</p>")),
Self::Informative {
full_name,
short_name,
url,
..
} => {
let x = full_name.clone().unwrap_or_else(|| {
short_name
.clone()
.unwrap_or_else(|| {
url.clone()
.map(|u| u.to_string())
.unwrap_or_else(|| "unknown".to_string())
})
.to_string()
});
match url {
Some(ref u) => crate::Html(format!(
"<p><a class=\"text-blue-900 hover:underline\" href={u}>{x}</a></p>"
)),
None => crate::Html(format!("<p>{x}</p>")),
}
}
}
}
}

#[derive(Deserialize, Debug, Serialize, Clone, Default)]
#[serde(untagged)]
pub enum LicenseType {
Single(LicenseT),
Multiple(Vec<LicenseT>),
pub enum Plurality<T> {
#[default]
None,
Single(T),
Multiple(Vec<T>),
Fallback(String),
}

impl<T: NixHtml + Eq + std::hash::Hash> NixHtml for Plurality<T> {
fn as_html(&self) -> crate::Html {
match self {
Self::None => crate::Html("<p></p>".to_string()),
Self::Single(l) => l.as_html(),
Self::Multiple(m) => crate::Html(m.iter().unique().map(|f| f.as_html().0).join("")),
Self::Fallback(m) => crate::Html(format!("<code>{m}</code>")),
}
}
}

impl Default for LicenseType {
fn default() -> Self {
LicenseType::Single(LicenseT::Verbatim("unknown".to_string()))
impl NixHtml for Url {
fn as_html(&self) -> crate::Html {
crate::Html(format!(
"<p><a class=\"text-blue-900 hover:underline\" href={self}>{self}</a></p>",
))
}
}

impl Display for LicenseType {
impl<T: Serialize> Display for Plurality<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&serde_json::to_string_pretty(self).unwrap_or_default())
}
Expand All @@ -82,10 +127,13 @@ pub struct NixPackage {
pub description: Option<String>,
#[serde(rename = "camelCase")]
pub long_description: Option<String>,
pub license: Option<LicenseType>,
#[serde(default)]
pub license: Plurality<License>,
pub name: String,
pub outputs: Vec<String>,
pub version: Option<String>,
#[serde(default)]
pub homepage: Plurality<Url>,
}

#[derive(RustEmbed)]
Expand Down
10 changes: 2 additions & 8 deletions src/search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ type FCFruit = ((f32, f32), DocAddress);
pub mod options;
pub mod packages;

#[allow(dead_code)]
pub struct SearcherInner {
schema: Schema,
index: tantivy::Index,
Expand Down Expand Up @@ -233,14 +232,9 @@ pub trait Searcher {
.expect("value is text")
.to_string();

let entry = self
.entries()
self.entries()
.get(&name)
.expect("found option is not indexed");

dbg!((_score, &entry));

entry
.expect("found option is not indexed")
})
.collect_vec()
})
Expand Down
6 changes: 2 additions & 4 deletions src/search/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};

use tantivy::collector::{Collector, TopDocs};
use tantivy::query::{Query, QueryParser};
use tantivy::schema::{Facet, FacetOptions, Schema, TextFieldIndexing, TextOptions, TEXT};
use tantivy::schema::{Facet, FacetOptions, Schema, TextOptions, TEXT};
use tantivy::{DocId, Document, Score, SegmentReader};

use super::{open_or_create_index, FCFruit, Searcher, SearcherInner};
Expand Down Expand Up @@ -62,9 +62,7 @@ impl Searcher for OptionsSearcher {
//query_parser.set_field_boost(name, 5.0);
//query_parser.set_conjunction_by_default();

let ret = query_parser.parse_query_lenient(query_string).0;
dbg!(&ret);
ret
query_parser.parse_query_lenient(query_string).0
}

/// creates the index and initializes the struct that holds
Expand Down
8 changes: 7 additions & 1 deletion tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
module.exports = {
content: ["src/*.rs", "templates/*.html"],
theme: {
extends: {},
extend: {
colors: {
'fc-green': '#52a46c',
'fc-midnight': '#002855',
'fc-blue-gray': '#d5dce7',
}
}
},
plugins: [],
};
69 changes: 69 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!doctype html>
<html lang="en">
<head>
<link href="/assets/tailwind.css" rel="stylesheet" />
<script src="https://unpkg.com/[email protected]" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous"></script>
<title>FC-Search</title>
<link href="https://flyingcircus.io/fileadmin/global-data/fira/fira-small.css" rel="stylesheet" />
<style>
body, html {
font-family: 'Fira Sans';
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body class="px-0">
<header>
<nav class="bg-fc-green border-gray-200 px-4 lg:px-6 py-2.5 dark:bg-gray-800">
<div class="flex flex-wrap justify-between items-center mx-auto max-w-screen-xl">
<a href="https://flyingcircus.io" class="flex items-center">
<img src="https://flyingcircus.io/fileadmin/global-data/logo/RZ_FC-Logo_RGB_INV-GR_100-1080.svg" class="mr-3 h-12 sm:h-12" alt="Flying Circus Logo" />
</a>
<div class="flex items-center lg:order-2">
<a href="https://flyingcircus.io/en/about-us/privacy-policy" class="text-white hover:text-fc-midnight dark:text-white hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-md text-sm px-4 lg:px-5 py-2 lg:py-2.5 mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">Privacy</a>
<a href="https://flyingcircus.io/en/about-us/legal-notice" class="text-white hover:text-fc-midnight dark:text-white hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-md text-sm px-4 lg:px-5 py-2 lg:py-2.5 mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">Imprint</a>
</div>
</div>
</nav>
</header>
<div class="flex justify-center my-10">
<h1 class="text-6xl">
{% block title %}
{% endblock %}
</h1>
</div>

<div class="flex justify-center w-full">
<form class="grow flex flex-col justify-center items-center"
hx-get="{% block search_endpoint %}{% endblock %}"
hx-trigger="input changed delay:200ms from:#search-input, search from:#search-input, change from:#channel"
hx-push-url="true"
hx-target="#search-results">

<input
class="rounded-md px-3 py-2 w-1/2 bg-fc-blue-gray" id="search-input"
type="search" name="q" placeholder="begin typing to search..."
value="{{search_value}}"
/>

<div class="px-3 py-2 m-3 outline outline-fc-blue-gray rounded-md">
<label class="pr-1" for="channel">Channel:</label>
<select name="channel" id="channel">
{% for branch in branches %}
<option value="{{branch}}">{{branch}}</option>
{% endfor %}
</select>
</div>
</form>
</div>

<div class="flex justify-center p-4">
<div class="flex justify-center w-2/3">
<ul class="grow" id="search-results">
{% block search_results %}
{% endblock %}
</ul>
</div>
</div>
</body>
</html>
50 changes: 6 additions & 44 deletions templates/options_index.html
Original file line number Diff line number Diff line change
@@ -1,47 +1,9 @@
<!doctype html>
<html lang="en">
<head>
<link href="/assets/tailwind.css" rel="stylesheet" />
<script src="https://unpkg.com/[email protected]" integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC" crossorigin="anonymous"></script>
<title>FC-Search</title>
</head>
<body>
<div class="flex justify-center my-10">
<h1 class="text-6xl">
Search NixOS Options
</h1>
</div>
{% extends "index.html" %}

<div class="flex justify-center w-full">
<form class="grow flex flex-col justify-center items-center"
hx-get="/search/options"
hx-trigger="input changed delay:200ms from:#search-input, search from:#search-input, change from:#channel"
hx-push-url="true"
hx-target="#search-results">
{% block title %}Search NixOS Options{% endblock %}

<input
class="rounded-full px-3 py-2 w-1/2 bg-gray-100" id="search-input"
type="search" name="q" placeholder="begin typing to search..."
value="{{search_value}}"
/>
{% block search_endpoint %}/search/options{% endblock %}

<div class="px-3 py-2 m-3 bg-gray-50 rounded-full">
<label class="pr-1" for="channel">Channel:</label>
<select name="channel" id="channel">
{% for branch in branches %}
<option value="{{branch}}">{{branch}}</option>
{% endfor %}
</select>
</div>
</form>
</div>

<div class="flex justify-center p-4">
<div class="flex justify-center w-2/3">
<ul class="grow" id="search-results">
{% include "option_item.html" %}
</ul>
</div>
</div>
</body>
</html>
{% block search_results %}
{% include "option_item.html" %}
{% endblock %}
17 changes: 6 additions & 11 deletions templates/package_item.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% for item in results %}
<li class="my-4 p-2 border border-2 rounded">
<li class="my-4 p-4 border border-1 rounded-md">

<p class="font-bold py-1">{{ item.attribute_name }}</p>
<p class="font-bold py-1 text-fc-green">{{ item.attribute_name }}</p>

<p>{{ item.description.clone().unwrap_or_default() }}</p>

Expand All @@ -11,19 +11,14 @@
{{ item.version.clone().unwrap_or_default() }}
</code>

<p>Name</p>
<code class="col-span-6">
{{ item.name }}
</code>

<p>Default Output</p>
<p>License</p>
<code class="col-span-6">
{{ item.default_output }}
{{ item.license.as_html()|safe }}
</code>

<p>License</p>
<p>Homepage</p>
<code class="col-span-6">
{{ item.license.clone().unwrap_or_default() }}
{{ item.homepage.as_html()|safe }}
</code>
</div>
</li>
Expand Down
Loading

0 comments on commit 7b159d6

Please sign in to comment.