167 lines
4.5 KiB
Rust
167 lines
4.5 KiB
Rust
// Copyright (C) 2026 Emilis Bliūdžius
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
use werewolves_proto::{
|
|
aura::AuraTitle, character::Character, game::Category, role::RoleTitle, team::Team,
|
|
};
|
|
|
|
pub trait PartialClass {
|
|
fn partial_class(&self) -> Option<&'static str>;
|
|
}
|
|
|
|
impl PartialClass for AuraTitle {
|
|
fn partial_class(&self) -> Option<&'static str> {
|
|
match self {
|
|
AuraTitle::Damned => Some("damned"),
|
|
AuraTitle::Drunk => Some("drunk"),
|
|
AuraTitle::Insane
|
|
| AuraTitle::Bloodlet
|
|
| AuraTitle::Scapegoat
|
|
| AuraTitle::RedeemableScapegoat
|
|
| AuraTitle::VindictiveScapegoat
|
|
| AuraTitle::SpitefulScapegoat
|
|
| AuraTitle::InevitableScapegoat => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait Class {
|
|
fn class(&self) -> &'static str;
|
|
}
|
|
|
|
impl Class for Character {
|
|
fn class(&self) -> &'static str {
|
|
if let Team::AnyEvil = self.team() {
|
|
return "damned";
|
|
}
|
|
|
|
self.role_title().category().class()
|
|
}
|
|
}
|
|
|
|
impl Class for RoleTitle {
|
|
fn class(&self) -> &'static str {
|
|
self.category().class()
|
|
}
|
|
}
|
|
|
|
impl Class for Category {
|
|
fn class(&self) -> &'static str {
|
|
match self {
|
|
Category::Wolves => "wolves",
|
|
Category::Villager => "village",
|
|
Category::Intel => "intel",
|
|
Category::Defensive => "defensive",
|
|
Category::Offensive => "offensive",
|
|
Category::StartsAsVillager => "starts-as-villager",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct Classes(Vec<String>);
|
|
impl<I> From<I> for Classes
|
|
where
|
|
I: Into<Vec<String>>,
|
|
{
|
|
fn from(value: I) -> Self {
|
|
Self(value.into())
|
|
}
|
|
}
|
|
impl core::fmt::Display for Classes {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str(self.0.join(" ").as_str())
|
|
}
|
|
}
|
|
|
|
pub trait AsClasses {
|
|
fn as_classes(&self) -> Classes;
|
|
}
|
|
|
|
impl AsClasses for [&str] {
|
|
fn as_classes(&self) -> Classes {
|
|
Classes(self.iter().map(|s| s.to_string()).collect())
|
|
}
|
|
}
|
|
|
|
impl leptos::tachys::html::class::IntoClass for Classes {
|
|
type AsyncOutput = Self;
|
|
type State = (leptos::tachys::renderer::types::Element, Self);
|
|
type Cloneable = Self;
|
|
type CloneableOwned = Self;
|
|
|
|
fn html_len(&self) -> usize {
|
|
let len = self.0.len();
|
|
self.0.iter().map(|c| c.len()).sum::<usize>()
|
|
+ if len == 2 {
|
|
1
|
|
} else if len > 2 {
|
|
len - 1
|
|
} else {
|
|
0
|
|
}
|
|
}
|
|
|
|
fn to_html(self, class: &mut String) {
|
|
class.push_str(self.0.join(" ").as_str());
|
|
}
|
|
|
|
fn should_overwrite(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn hydrate<const FROM_SERVER: bool>(
|
|
self,
|
|
el: &leptos::tachys::renderer::types::Element,
|
|
) -> Self::State {
|
|
if !FROM_SERVER {
|
|
leptos::tachys::renderer::Rndr::set_attribute(el, "class", self.to_string().as_str());
|
|
}
|
|
(el.clone(), self)
|
|
}
|
|
|
|
fn build(self, el: &leptos::tachys::renderer::types::Element) -> Self::State {
|
|
leptos::tachys::renderer::Rndr::set_attribute(el, "class", self.to_string().as_str());
|
|
(el.clone(), self)
|
|
}
|
|
|
|
fn rebuild(self, state: &mut Self::State) {
|
|
let (el, prev) = state;
|
|
if self != *prev {
|
|
leptos::tachys::renderer::Rndr::set_attribute(el, "class", self.to_string().as_str());
|
|
}
|
|
*prev = self;
|
|
}
|
|
|
|
fn into_cloneable(self) -> Self::Cloneable {
|
|
self
|
|
}
|
|
|
|
fn into_cloneable_owned(self) -> Self::CloneableOwned {
|
|
self.into()
|
|
}
|
|
|
|
fn dry_resolve(&mut self) {}
|
|
|
|
async fn resolve(self) -> Self::AsyncOutput {
|
|
self
|
|
}
|
|
|
|
fn reset(state: &mut Self::State) {
|
|
let (el, _prev) = state;
|
|
leptos::tachys::renderer::Rndr::remove_attribute(el, "class");
|
|
}
|
|
}
|