mirror of
https://codeberg.org/demostf/frontend.git
synced 2026-06-03 18:24:12 +02:00
inline js data
This commit is contained in:
parent
7a2f4d1af0
commit
1e2a3e28e7
8 changed files with 111 additions and 69 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
mod script;
|
mod script;
|
||||||
mod style;
|
mod style;
|
||||||
|
|
||||||
|
use base64::engine::general_purpose::STANDARD;
|
||||||
|
use base64::Engine;
|
||||||
use fnv::FnvHasher;
|
use fnv::FnvHasher;
|
||||||
pub use script::bundle_script;
|
pub use script::bundle_script;
|
||||||
use std::fs::read;
|
use std::fs::read;
|
||||||
|
|
@ -43,3 +45,20 @@ pub fn guess_mime(path: &str) -> &'static str {
|
||||||
}
|
}
|
||||||
return "text/plain";
|
return "text/plain";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inline_url(path: &str) -> String {
|
||||||
|
let content = read(path).unwrap_or_else(|e| {
|
||||||
|
eprintln!("Failed to write inline file {path}: {e}");
|
||||||
|
panic!("Failed to inline");
|
||||||
|
});
|
||||||
|
let (mime, encode) = guess_embed(path);
|
||||||
|
|
||||||
|
if encode {
|
||||||
|
let encoded = STANDARD.encode(content);
|
||||||
|
format!("data:{mime};base64,{encoded}")
|
||||||
|
} else {
|
||||||
|
let content = String::from_utf8(content).expect("invalid utf8");
|
||||||
|
let encoded = urlencoding::encode(&content);
|
||||||
|
format!("data:{mime},{encoded}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
39
build/bundlers/src/script/inline.rs
Normal file
39
build/bundlers/src/script/inline.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
use crate::inline_url;
|
||||||
|
use swc_core::ecma::{
|
||||||
|
ast::*,
|
||||||
|
visit::{VisitMut, VisitMutWith},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct InlineVisitor {}
|
||||||
|
|
||||||
|
impl InlineVisitor {
|
||||||
|
fn visit_require(&mut self, expr: &mut Expr, path: &str) {
|
||||||
|
if let Some(path) = path.strip_prefix("inline://") {
|
||||||
|
let data = inline_url(path);
|
||||||
|
*expr = Expr::Lit(Lit::Str(data.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VisitMut for InlineVisitor {
|
||||||
|
fn visit_mut_expr(&mut self, expr: &mut Expr) {
|
||||||
|
if let Expr::Call(CallExpr {
|
||||||
|
args,
|
||||||
|
callee: Callee::Expr(callee),
|
||||||
|
..
|
||||||
|
}) = expr
|
||||||
|
{
|
||||||
|
if let Expr::Ident(callee) = callee.as_ref() {
|
||||||
|
if callee.sym.as_ref() == "require" {
|
||||||
|
if let Some(arg) = args.first() {
|
||||||
|
if let Expr::Lit(Lit::Str(arg)) = arg.expr.as_ref() {
|
||||||
|
let path = arg.value.to_string();
|
||||||
|
self.visit_require(expr, &path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expr.visit_mut_children_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
mod inline;
|
||||||
|
|
||||||
|
use crate::script::inline::InlineVisitor;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use jsx_dom_expressions::TransformVisitor;
|
use jsx_dom_expressions::TransformVisitor;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
@ -153,6 +156,7 @@ impl Load for Loader {
|
||||||
|
|
||||||
let module = module
|
let module = module
|
||||||
.fold_with(&mut strip(top_level_mark))
|
.fold_with(&mut strip(top_level_mark))
|
||||||
|
.fold_with(&mut as_folder(InlineVisitor {}))
|
||||||
.fold_with(&mut as_folder(TransformVisitor::new(
|
.fold_with(&mut as_folder(TransformVisitor::new(
|
||||||
jsx_dom_expressions::config::Config {
|
jsx_dom_expressions::config::Config {
|
||||||
module_name: "solid-js/web".to_string(),
|
module_name: "solid-js/web".to_string(),
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::guess_embed;
|
use crate::inline_url;
|
||||||
use base64::engine::general_purpose::STANDARD;
|
|
||||||
use base64::Engine;
|
|
||||||
use lightningcss::bundler::{Bundler, FileProvider};
|
use lightningcss::bundler::{Bundler, FileProvider};
|
||||||
use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions};
|
use lightningcss::stylesheet::{MinifyOptions, ParserOptions, PrinterOptions};
|
||||||
use lightningcss::targets::Browsers;
|
use lightningcss::targets::Browsers;
|
||||||
|
|
@ -8,7 +6,6 @@ use lightningcss::values::url::Url;
|
||||||
use lightningcss::visit_types;
|
use lightningcss::visit_types;
|
||||||
use lightningcss::visitor::{Visit, VisitTypes, Visitor};
|
use lightningcss::visitor::{Visit, VisitTypes, Visitor};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::fs::read;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn bundle_style(style: &str) -> Vec<u8> {
|
pub fn bundle_style(style: &str) -> Vec<u8> {
|
||||||
|
|
@ -61,20 +58,7 @@ impl<'i> Visitor<'i> for InlineUrlVisitor {
|
||||||
|
|
||||||
fn visit_url(&mut self, url: &mut Url<'i>) -> Result<(), Self::Error> {
|
fn visit_url(&mut self, url: &mut Url<'i>) -> Result<(), Self::Error> {
|
||||||
if let Some(path) = url.url.strip_prefix("inline://") {
|
if let Some(path) = url.url.strip_prefix("inline://") {
|
||||||
let content = read(path).unwrap_or_else(|e| {
|
url.url = inline_url(path).into();
|
||||||
eprintln!("Failed to write inline file {path}: {e}");
|
|
||||||
panic!("Failed to inline");
|
|
||||||
});
|
|
||||||
let (mime, encode) = guess_embed(path);
|
|
||||||
|
|
||||||
if encode {
|
|
||||||
let encoded = STANDARD.encode(content);
|
|
||||||
url.url = format!("data:{mime};base64,{encoded}").into();
|
|
||||||
} else {
|
|
||||||
let content = String::from_utf8(content).expect("invalid utf8");
|
|
||||||
let encoded = urlencoding::encode(&content);
|
|
||||||
url.url = format!("data:{mime},{encoded}").into();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ ready(async () => {
|
||||||
|
|
||||||
const parse = async (data: ArrayBuffer, parseProgress: HTMLProgressElement, stored: boolean) => {
|
const parse = async (data: ArrayBuffer, parseProgress: HTMLProgressElement, stored: boolean) => {
|
||||||
const header = parseHeaderFromBuffer(data);
|
const header = parseHeaderFromBuffer(data);
|
||||||
|
console.log(header);
|
||||||
const parser = new AsyncParser(data, (progress) => parseProgress.value = progress);
|
const parser = new AsyncParser(data, (progress) => parseProgress.value = progress);
|
||||||
await parser.cache();
|
await parser.cache();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,30 +16,24 @@ const healthMap = [0, 150, 180, 216];
|
||||||
function getBuildingType(type: BuildingType) {
|
function getBuildingType(type: BuildingType) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BuildingType.TeleporterEntrance:
|
case BuildingType.TeleporterEntrance:
|
||||||
return 'tele_entrance';
|
return require("inline://images/building_icons/tele_entrance.png");
|
||||||
case BuildingType.TeleporterExit:
|
case BuildingType.TeleporterExit:
|
||||||
return 'tele_exit';
|
return require("inline://images/building_icons/tele_exit.png");
|
||||||
case BuildingType.Dispenser:
|
case BuildingType.Dispenser:
|
||||||
return 'dispenser';
|
return require("inline://images/building_icons/dispenser.png");
|
||||||
case BuildingType.Level1Sentry:
|
case BuildingType.Level1Sentry:
|
||||||
return 'sentry_1';
|
return require("inline://images/building_icons/sentry_1.png");
|
||||||
case BuildingType.Level2Sentry:
|
case BuildingType.Level2Sentry:
|
||||||
return 'sentry_2';
|
return require("inline://images/building_icons/sentry_2.png");
|
||||||
case BuildingType.Level3Sentry:
|
case BuildingType.Level3Sentry:
|
||||||
return 'sentry_3';
|
return require("inline://images/building_icons/sentry_3.png");
|
||||||
case BuildingType.MiniSentry:
|
case BuildingType.MiniSentry:
|
||||||
return 'sentry_1';
|
return require("inline://images/building_icons/sentry_1.png");
|
||||||
default:
|
default:
|
||||||
return 'unknown';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIcon(building: BuildingState) {
|
|
||||||
const icon = getBuildingType(building.buildingType);
|
|
||||||
const team = building.team === Team.Red ? 'red' : 'blue';
|
|
||||||
return `/images/building_icons/${icon}_${team}.png`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Building(props: BuildingProp) {
|
export function Building(props: BuildingProp) {
|
||||||
const worldWidth = props.mapBoundary.boundary_max.x - props.mapBoundary.boundary_min.x;
|
const worldWidth = props.mapBoundary.boundary_max.x - props.mapBoundary.boundary_min.x;
|
||||||
const worldHeight = props.mapBoundary.boundary_max.y - props.mapBoundary.boundary_min.y;
|
const worldHeight = props.mapBoundary.boundary_max.y - props.mapBoundary.boundary_min.y;
|
||||||
|
|
@ -48,6 +42,7 @@ export function Building(props: BuildingProp) {
|
||||||
const scaledX = () => x() / worldWidth * props.targetSize.width;
|
const scaledX = () => x() / worldWidth * props.targetSize.width;
|
||||||
const scaledY = () => (worldHeight - y()) / worldHeight * props.targetSize.height;
|
const scaledY = () => (worldHeight - y()) / worldHeight * props.targetSize.height;
|
||||||
const maxHealth = () => healthMap[props.building.level];
|
const maxHealth = () => healthMap[props.building.level];
|
||||||
|
const teamColor = () => (props.building.team === Team.Red) ? '#a75d50' : '#5b818f';
|
||||||
if (!maxHealth) {
|
if (!maxHealth) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -57,10 +52,12 @@ export function Building(props: BuildingProp) {
|
||||||
|
|
||||||
const alpha = () => props.building.health / maxHealth;
|
const alpha = () => props.building.health / maxHealth;
|
||||||
try {
|
try {
|
||||||
const image = getIcon(props.building);
|
const image = () => getBuildingType(props.building.buildingType);
|
||||||
return <g transform={transform()}
|
return <g transform={transform()}
|
||||||
opacity={alpha()}>
|
opacity={alpha()}>
|
||||||
<image href={image} className={"player-icon"} height={32}
|
<circle r={16} stroke-width={1} stroke="white" fill={teamColor()}
|
||||||
|
opacity={alpha()}/>
|
||||||
|
<image href={image()} className={"player-icon"} height={32}
|
||||||
width={32}
|
width={32}
|
||||||
transform={`translate(-16 -16)`}/>
|
transform={`translate(-16 -16)`}/>
|
||||||
<Show when={props.building.angle}>
|
<Show when={props.building.angle}>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import {PlayerState, WorldBoundaries, Team} from "../Data/Parser";
|
import {PlayerState, WorldBoundaries, Team} from "../Data/Parser";
|
||||||
import {createEffect} from "solid-js";
|
|
||||||
|
|
||||||
export interface PlayerProp {
|
export interface PlayerProp {
|
||||||
player: PlayerState;
|
player: PlayerState;
|
||||||
|
|
@ -24,17 +23,17 @@ const healthMap = {
|
||||||
9: 125,//engineer
|
9: 125,//engineer
|
||||||
};
|
};
|
||||||
|
|
||||||
const classMap = {
|
const imageMap = {
|
||||||
0: "empty",
|
0: require("inline://images/class_icons/empty.svg"),
|
||||||
1: "scout",
|
1: require("inline://images/class_icons/scout.svg"),
|
||||||
2: "sniper",
|
2: require("inline://images/class_icons/sniper.svg"),
|
||||||
3: "soldier",
|
3: require("inline://images/class_icons/soldier.svg"),
|
||||||
4: "demoman",
|
4: require("inline://images/class_icons/demoman.svg"),
|
||||||
5: "medic",
|
5: require("inline://images/class_icons/medic.svg"),
|
||||||
6: "heavy",
|
6: require("inline://images/class_icons/heavy.svg"),
|
||||||
7: "pyro",
|
7: require("inline://images/class_icons/pyro.svg"),
|
||||||
8: "spy",
|
8: require("inline://images/class_icons/spy.svg"),
|
||||||
9: "engineer"
|
9: require("inline://images/class_icons/engineer.svg"),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Player(props: PlayerProp) {
|
export function Player(props: PlayerProp) {
|
||||||
|
|
@ -63,11 +62,10 @@ export function Player(props: PlayerProp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getClassImage(player: PlayerState, imageOpacity: number) {
|
function getClassImage(player: PlayerState, imageOpacity: number) {
|
||||||
if (!classMap[player.playerClass]) {
|
if (!imageMap[player.playerClass]) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const image = `/images/class_icons/${classMap[player.playerClass]}.svg`;
|
return <image href={imageMap[player.playerClass]}
|
||||||
return <image href={image}
|
|
||||||
class={"player-icon " + player.team}
|
class={"player-icon " + player.team}
|
||||||
opacity={imageOpacity}
|
opacity={imageOpacity}
|
||||||
height={32}
|
height={32}
|
||||||
|
|
|
||||||
|
|
@ -87,34 +87,34 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
& .class-icon.scout {
|
& .class-icon.scout {
|
||||||
background-image: url('../../images/class_portraits/Icon_scout.jpg');
|
background-image: url('/images/class_portraits/Icon_scout.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.soldier {
|
& .class-icon.soldier {
|
||||||
background-image: url('../../images/class_portraits/Icon_soldier.jpg');
|
background-image: url('/images/class_portraits/Icon_soldier.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.pyro {
|
& .class-icon.pyro {
|
||||||
background-image: url('../../images/class_portraits/Icon_pyro.jpg');
|
background-image: url('/images/class_portraits/Icon_pyro.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.demoman {
|
& .class-icon.demoman {
|
||||||
background-image: url('../../images/class_portraits/Icon_demoman.jpg');
|
background-image: url('/images/class_portraits/Icon_demoman.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.engineer {
|
& .class-icon.engineer {
|
||||||
background-image: url('../../images/class_portraits/Icon_engineer.jpg');
|
background-image: url('/images/class_portraits/Icon_engineer.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.heavy {
|
& .class-icon.heavy {
|
||||||
background-image: url('../../images/class_portraits/Icon_heavy.jpg');
|
background-image: url('/images/class_portraits/Icon_heavy.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.medic {
|
& .class-icon.medic {
|
||||||
background-image: url('../../images/class_portraits/Icon_medic.jpg');
|
background-image: url('/images/class_portraits/Icon_medic.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.sniper {
|
& .class-icon.sniper {
|
||||||
background-image: url('../../images/class_portraits/Icon_sniper.jpg');
|
background-image: url('/images/class_portraits/Icon_sniper.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.spy{
|
& .class-icon.spy{
|
||||||
background-image: url('../../images/class_portraits/Icon_spy.jpg');
|
background-image: url('/images/class_portraits/Icon_spy.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.uber {
|
& .class-icon.uber {
|
||||||
background-image: url('images/charge_red.svg');
|
background-image: url('inline://images/charge_red.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
& .class-icon, & .steam-avatar {
|
& .class-icon, & .steam-avatar {
|
||||||
|
|
@ -148,34 +148,34 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
& .class-icon.scout {
|
& .class-icon.scout {
|
||||||
background-image: url('../../images/class_portraits/Icon_scout_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_scout_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.soldier {
|
& .class-icon.soldier {
|
||||||
background-image: url('../../images/class_portraits/Icon_soldier_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_soldier_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.pyro {
|
& .class-icon.pyro {
|
||||||
background-image: url('../../images/class_portraits/Icon_pyro_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_pyro_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.demoman {
|
& .class-icon.demoman {
|
||||||
background-image: url('../../images/class_portraits/Icon_demoman_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_demoman_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.engineer {
|
& .class-icon.engineer {
|
||||||
background-image: url('../../images/class_portraits/Icon_engineer_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_engineer_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.heavy {
|
& .class-icon.heavy {
|
||||||
background-image: url('../../images/class_portraits/Icon_heavy_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_heavy_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.medic {
|
& .class-icon.medic {
|
||||||
background-image: url('../../images/class_portraits/Icon_medic_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_medic_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.sniper {
|
& .class-icon.sniper {
|
||||||
background-image: url('../../images/class_portraits/Icon_sniper_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_sniper_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.spy {
|
& .class-icon.spy {
|
||||||
background-image: url('../../images/class_portraits/Icon_spy_blue.jpg');
|
background-image: url('/images/class_portraits/Icon_spy_blue.jpg');
|
||||||
}
|
}
|
||||||
& .class-icon.uber {
|
& .class-icon.uber {
|
||||||
background-image: url('images/charge_blue.svg');
|
background-image: url('inline://images/charge_blue.svg');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue