index should almost be done

This commit is contained in:
Maieul BOYER 2026-02-07 23:49:51 +01:00
parent 8e82ec9523
commit bbc7cda33f
Signed by: maix
SSH key fingerprint: SHA256:iqCzqFFF5KjRixmDExqbAltCIj9ndlBWIGJf3t9Ln9g
3 changed files with 269 additions and 63 deletions

View file

@ -0,0 +1,86 @@
use std::collections::HashMap;
use froxy_templates::index::{self, ClusterData, IndexData, LocationData, MapPos, PcIssue};
use smol_str::SmolStr;
fn main() {
let mut env = minijinja::Environment::new();
index::add_to_context(&mut env);
let data = index::render(
&env,
IndexData {
clusters: HashMap::from([(
SmolStr::new_static("F1"),
ClusterData {
users: 80,
max_pc: 100,
dead_pc: 1,
silent: false,
piscine: true,
issues: [
(SmolStr::new_static("F1r1s1"), PcIssue::Dead),
(SmolStr::new_static("F1r2s1"), PcIssue::Attention),
]
.into_iter()
.collect(),
map: index::Map {
rows: [
index::MapRow {
range: SmolStr::new_static("R1"),
col: [
MapPos::Empty,
MapPos::Flex,
MapPos::Wall,
MapPos::Door,
MapPos::Empty,
]
.to_vec(),
},
index::MapRow {
range: SmolStr::new_static("R2"),
col: [
MapPos::Empty,
MapPos::Flex,
MapPos::Pc(SmolStr::new_static("F1r1s1")),
MapPos::Pc(SmolStr::new_static("F1r2s1")),
MapPos::Pc(SmolStr::new_static("F1r3s1")),
MapPos::Pc(SmolStr::new_static("F1r4s1")),
MapPos::Pc(SmolStr::new_static("F1r5s1")),
MapPos::Empty,
]
.to_vec(),
},
index::MapRow {
range: SmolStr::new_static("R3"),
col: [
MapPos::Empty,
MapPos::Flex,
MapPos::Wall,
MapPos::Door,
MapPos::Empty,
]
.to_vec(),
},
]
.to_vec(),
},
},
)]),
locations: [(SmolStr::new_static("F1r5s1"), LocationData {
login: "maiboyer".into(),
image: "https://friends.42paris.fr/proxy/resize/512/03c61af252becbca11aac5ff49a2e61c/maiboyer.jpg".into(),
me: false,
friend: false,
close_friend: false,
pooled: false,
})]
.into_iter()
.collect(),
current_cluster: SmolStr::new_static("F1"),
},
)
.unwrap();
println!("{data}");
}

View file

@ -1,3 +1,7 @@
use std::collections::HashMap;
use smol_str::SmolStr;
pub use crate::templates::INDEX;
pub fn add_to_context(env: &mut minijinja::Environment) {
@ -8,4 +12,110 @@ pub fn add_to_context(env: &mut minijinja::Environment) {
crate::open_modal::add_to_context(env);
}
env.add_template("index.html", INDEX).unwrap();
env.add_function("max", |a: i32, b: i32| -> i32 { a.max(b) });
}
pub fn render(env: &minijinja::Environment, data: IndexData) -> Result<String, minijinja::Error> {
let template = env.get_template("index.html")?;
template.render(data)
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocationData {
pub login: SmolStr,
pub image: String,
pub me: bool,
pub friend: bool,
pub close_friend: bool,
pub pooled: bool,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ClusterData {
pub users: u32,
pub dead_pc: u32,
pub max_pc: u32,
pub silent: bool,
pub piscine: bool,
pub map: Map,
pub issues: HashMap<SmolStr, PcIssue>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
#[serde(try_from = "SmolStr", into = "SmolStr")]
pub enum PcIssue {
#[default]
Dead,
Attention,
}
impl TryFrom<SmolStr> for PcIssue {
type Error = &'static str;
fn try_from(value: SmolStr) -> Result<Self, &'static str> {
Ok(match value.as_str() {
"dead" => Self::Dead,
"attention" => Self::Attention,
_ => return Err("Invalid string"),
})
}
}
impl From<PcIssue> for SmolStr {
fn from(val: PcIssue) -> Self {
match val {
PcIssue::Dead => SmolStr::new_static("dead"),
PcIssue::Attention => SmolStr::new_static("attention"),
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(from = "SmolStr", into = "SmolStr")]
pub enum MapPos {
Wall,
Flex,
Empty,
Door,
Pc(SmolStr),
}
impl From<SmolStr> for MapPos {
fn from(value: SmolStr) -> Self {
match value.as_str() {
"x" => Self::Wall,
"f" => Self::Flex,
"" => Self::Empty,
"d" => Self::Door,
_ => Self::Pc(value),
}
}
}
impl From<MapPos> for SmolStr {
fn from(val: MapPos) -> Self {
match val {
MapPos::Wall => SmolStr::new_static("x"),
MapPos::Flex => SmolStr::new_static("f"),
MapPos::Door => SmolStr::new_static("d"),
MapPos::Empty => SmolStr::new_static(""),
MapPos::Pc(s) => s,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct MapRow {
pub range: SmolStr,
pub col: Vec<MapPos>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Map {
pub rows: Vec<MapRow>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct IndexData {
pub locations: HashMap<SmolStr, LocationData>,
pub clusters: HashMap<SmolStr, ClusterData>,
pub current_cluster: SmolStr,
}

View file

@ -58,13 +58,48 @@
<div class="text-center">
<div class="btn-group mb-1 btn-width" role="group" aria-label="Change cluster">
{% for cluster in clusters %}
{% for name in clusters %}
<input type="radio" class="btn-check cluster_radios" name="btn-radio"
data-cluster="{{ cluster.name }}" id="radio{{ cluster.name }}"
autocomplete="off" {{ "checked" if actual_cluster == cluster['name'] else "" }}>
<label title="{{ (int(cluster.users / (cluster.maximum_places - cluster.dead_pc) * 100) if (cluster.maximum_places - cluster.dead_pc) > 0 else 0 ) }}%" class="btn btn-outline-{{ place_to_btn(cluster) }} m-t" for="radio{{ cluster.name }}">
{{ ('<i class="fa-solid fa-person-swimming text-info"></i>' if cluster.name in piscine else '') | safe }}{{ (' ' if cluster.name in piscine and cluster.name in silent else '') | safe }}{{ ('<i class="fa-solid fa-volume-xmark text-secondary"></i> ' if cluster.name in silent else '') | safe }}{{ cluster.name }}
<span class="text-muted">{{ cluster.users }}/{{ cluster.maximum_places - cluster.dead_pc }}</span></label>
data-cluster="{{ name }}" id="radio{{ name }}"
autocomplete="off">
{% set cluster = clusters[name] %}
{% set piscine = "" %}
{% set silent = "" %}
{% set spacer = "" %}
{%- if cluster.piscine -%}
{% set piscine = '<i class="fa-solid fa-person-swimming text-info"></i>' %}
{%- endif -%}
{%- if cluster.silent -%}
{% set piscine = '<i class="fa-solid fa-volume-xmark text-secondary"></i>' %}
{%- endif -%}
{%- if cluster.piscine and cluster.silent -%}
{% set spacer = " " %}
{%- endif -%}
{% set u = cluster.users %}
{% set m = cluster.max_pc - cluster.dead_pc %}
{%- if m < 0 -%}
{% set m = 0 %}
{%- endif -%}
{% set percent = 0 %}
{%- if m > 0 -%}
{% set percent = (u * 100) / m %}
{%- endif -%}
{% set fill_level = 'primary' %}
{%- if percent > 75 -%}
{% set fill_level = 'danger' %}
{%- elif percent > 65 -%}
{% set fill_level = 'warning' %}
{% endif%}
<label title="{{ percent | int }}%" class="btn btn-outline-{{ fill_level }} m-t" for="radio{{ name }}">
{{ piscine | safe }}{{ spacer | safe }}{{ silent | safe }} {{ name }}
<span class="text-muted">{{ u }}/{{ m }}</span></label>
{%- endfor -%}
</div>
</div>
@ -72,86 +107,61 @@
<table class="grid text-center">
<tbody>
{% for index, x in enumerate(map[1:], 0) %}
{% set map = clusters[current_cluster].map %}
{% set cluster = clusters[current_cluster] %}
{% for row in map.rows %}
<tr>
{%- set countB = namespace(value=1) -%}
<td class="range">{{ map[0][index] }}</td>
{%- for y in x -%}
{%- if y == 'x' -%}
{%- set countB = 0 -%}
<td class="range">{{ row.range }}</td>
{%- for col in row.col -%}
{%- if col == 'x' -%}
<td class="range">&nbsp;</td>
{%- elif y == '|' -%}
{%- elif col == '|' -%}
<td class="range-no-color"></td>
{%- elif y == 'h' -%}
{%- elif col == 'h' -%}
<td></td>
{%- elif y == 'd' -%}
{%- elif col == 'd' -%}
<td><i class="fa-solid fa-person-walking fa-2xl"></i></td>
{%- elif y == 'f' -%}
{%- elif col == 'f' -%}
<td><i class="fa-solid fa-laptop fa-xl"></i></td>
{%- elif exrypz(y) == False -%}
{%- elif col == '' -%}
<td class="small-colors"></td>
{%- else -%}
{%- set text_color = '' -%}
{%- set img = '<i class="fa-solid fa-user"></i>' -%}
{%- if y in locations -%}
{%- set img = '<img loading="lazy" class="profile-pic2" alt="" src="' + (custom_image(locations[y]['user']['login']) if locations[y]['has_custom_image'] else proxy_images(locations[y]['user']['image']['versions']['small'])) + '">' -%}
{%- elif actual_cluster in piscine and y in tutor_station -%}
{%- set img = '<i class="fa-solid fa-shield tutor-shield"></i>' -%}
{%- if col in locations -%}
{%- set img = '<img loading="lazy" class="profile-pic2" alt="" src="' + locations[col].image + '">' -%}
{%- endif -%}
{%- if actual_cluster in piscine and y in tutor_station -%}
{%- set text_color = 'tutor-shield' -%}
{%- endif -%}
{%- set relation = '' -%}
{%- set currently_in_piscine = y in locations and (locations[y]['user']['pool_month'], locations[y]['user']['pool_year']) in piscine_date -%}
{%- set in_piscine_cluster = actual_cluster in piscine -%}
{%- if y in locations and locations[y]['user']['id'] not in tutors and currently_in_piscine != in_piscine_cluster -%}
{%- set relation = 'wrong-cluster' -%}
{%- endif -%}
{%- if focus and focus == y %}
{%- if focus and focus == col %}
{%- set relation = 'focus' -%}
{%- elif y in locations and locations[y]['me'] -%}
{%- elif col in locations and locations[col].me -%}
{%- set relation = 'me' -%}
{%- elif y in locations and locations[y]['whitelist'] -%}
{%- set relation = 'whitelist' -%}
{%- elif y in locations and locations[y]['close_friend'] -%}
{%- elif col in locations and locations[col].close_friend -%}
{%- set relation = 'close_friend' -%}
{%- elif y in locations and locations[y]['friend'] -%}
{%- elif col in locations and locations[col].friend -%}
{%- set relation = 'friend' -%}
{%- elif y in issues_map and issues_map[y]['count'] >= 1 and issues_map[y]['issue'] == 1 -%}
{%- set relation = 'dead' -%}
{%- elif y in issues_map and issues_map[y]['count'] >= 1 and issues_map[y]['issue'] == 2 -%}
{%- set relation = 'attention' -%}
{%- elif y in locations and locations[y]['pool'] and actual_cluster not in piscine -%}
{%- elif col in cluster.issues -%}
{%- set relation = cluster.issues[col] -%}
{%- elif col in locations and locations[col]['pool'] and not cluster.piscine -%}
{%- set relation = 'pooled' -%}
{%- endif -%}
{%- if actual_cluster in piscine and y in locations and locations[y]['user']['id'] in tutors -%}
{%- set relation = 'tutor' -%}
{%- set text_color = '' -%}
{%- elif actual_cluster in piscine and y in locations and not locations[y]['user']['tutor'] in tutors and y in tutor_station -%}
{%- set relation = 'tutor-spot' -%}
{%- set text_color = '' -%}
{%- endif -%}
{%- if y in locations and locations[y]['admin'] -%}
{%- set relation = 'admin' -%}
{%- endif -%}
{%- if countB.value % 2 == 0 -%}
<td data-pos="{{ y }}"
data-login="{{ locations[y]['user']['login'] if y in locations else '' }}"
class="sm-t case {{ relation }} {{ text_color }}">{{ img|safe }}<br>{{ y.replace(actual_cluster, '') }}
{% set loc_name = col|replace(current_cluster, "") %}
<td data-pos="{{ col }}"
data-login="{{ locations[col].login if col in locations else '' }}"
class="sm-t case {{ relation }}">
{%- if countB % 2 == 0 -%}
{{ img|safe }}<br>{{ loc_name }}
{%- else -%}
{{ loc_name }}<br>{{ img|safe }}
{%- endif -%}
</td>
{%- else -%}
<td data-pos="{{ y }}"
data-login="{{ locations[y]['user']['login'] if y in locations else '' }}"
class="sm-t case {{ relation }} {{ text_color }}">{{ y.replace(actual_cluster, '') }}<br>{{ img|safe }}
</td>
{%- endif -%}
{%- endif -%}
{%- set countB.value = countB.value + 1 -%}
{%- set countB = (countB + 1) % 2 -%}
{%- endfor -%}
<td class="range">{{ map[0][index] }}</td>
<td class="range">{{ row.range }}</td>
</tr>
{%- endfor -%}
</tbody>