From 430c81bd2056769e1326df9d1dff983afe7f33df Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Tue, 14 Jul 2026 03:05:42 -0400 Subject: fix(admin): tech tab loading yaml and css --- data/.admin_history.json | 1 - data/techs/amplifier_1.yaml | 1 - data/techs/amplifier_2.yaml | 1 - data/techs/amplifier_3.yaml | 1 - data/techs/clarity_1.yaml | 1 - data/techs/clarity_2.yaml | 1 - data/techs/clarity_3.yaml | 1 - data/techs/focus_1.yaml | 1 - data/techs/focus_2.yaml | 1 - data/techs/focus_3.yaml | 1 - data/techs/fortify.yaml | 1 - data/techs/overclock.yaml | 1 - data/techs/preserve.yaml | 1 - data/techs/protect_melee.yaml | 1 - data/techs/protect_ranged.yaml | 1 - data/techs/protect_science.yaml | 1 - data/techs/rapid_heal.yaml | 1 - data/techs/regen.yaml | 1 - data/techs/retribution.yaml | 1 - data/techs/shield_1.yaml | 1 - data/techs/shield_2.yaml | 1 - data/techs/shield_3.yaml | 1 - data/techs/targeting_1.yaml | 1 - data/techs/targeting_2.yaml | 1 - data/techs/targeting_3.yaml | 1 - internal/admin/api_techs.go | 30 +++-- internal/admin/static/admin.css | 1 + internal/admin/static/techeditor.js | 220 ++++++++++++++++++++++++++++++++++-- internal/game/core_validate.go | 1 - internal/game/sys_technology.go | 1 - internal/validate/checks.go | 7 -- internal/validate/validate.go | 6 - 32 files changed, 231 insertions(+), 60 deletions(-) delete mode 100644 data/.admin_history.json diff --git a/data/.admin_history.json b/data/.admin_history.json deleted file mode 100644 index 1bafd70..0000000 --- a/data/.admin_history.json +++ /dev/null @@ -1 +0,0 @@ -{"history":[{"time":"2026-07-14T01:27:45-04:00","description":"delete course test (last obstacle removed)","file_path":"data/courses/test.yaml","old_content":"completion_xp: 0\nname: test\nobstacles:\n - exit_dir: southwest\n fail_damage:\n - 0\n - 0\n phases: []\n room_id: 1009\n verb: climb\n xp: 0\nrequired_level: 1\nstart_room: 1007\n","new_content":"","is_delete":true,"is_create":false},{"time":"2026-07-14T01:27:45-04:00","description":"delete 3 rooms (cleaned 2 exits)","file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n south:\n always_blocked: false\n blocked_message: \"\"\n condition: null\n hidden: false\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\non_enter:\n - condition:\n all_of: []\n steps: []\n - steps: []\n - steps: []\non_exit:\n - steps: []\n - steps: []\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/intro/1007.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1010\n north:\n room: 1008\n south:\n room: 1005\nhazard: \"\"\nid: 1007\nitem_spawns: []\nmobs: []\nname: 'Room #1007'\nobjects: []\non_enter: []\non_exit: []\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1010\n south:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"},{"file_path":"data/rooms/intro/1010.yaml","old_content":"block_transport: false\ncolor: D3\nexits:\n south:\n room: 1009\nhazard: \"\"\nid: 1010\nname: 'Room #1011'\n","new_content":"id: 1010\nname: 'Room #1011'\ncolor: D3\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"},{"file_path":"data/rooms/intro/1011.yaml","old_content":"color: D3\nexits:\n south:\n room: 1009\nid: 1011\nname: 'Room #1011'\n","new_content":"","is_delete":true},{"file_path":"data/rooms/intro/1009.yaml","old_content":"color: D3\nexits:\n south:\n room: 1009\nid: 1009\nname: 'Room #1011'\n","new_content":"","is_delete":true}]},{"time":"2026-07-14T01:27:52-04:00","description":"delete room 1010 (cleaned 1 exits)","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: 'Room #1011'\ncolor: D3\ndescription: []\nexits: {}\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n","new_content":"","is_delete":true,"is_create":false,"extra_files":[{"file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1010\n south:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"}]},{"time":"2026-07-14T01:27:58-04:00","description":"create room 1008","file_path":"data/rooms/intro/1008.yaml","old_content":"","new_content":"color: D3\nexits:\n west:\n room: 1007\nid: 1008\nname: 'Room #1008'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/intro/1007.yaml","old_content":"id: 1007\nname: 'Room #1007'\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n","new_content":"id: 1007\nname: 'Room #1007'\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1008\n south:\n room: 1005\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"}]},{"time":"2026-07-14T01:27:59-04:00","description":"create room 1009","file_path":"data/rooms/intro/1009.yaml","old_content":"","new_content":"color: D3\nexits:\n south:\n room: 1008\nid: 1009\nname: 'Room #1009'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/intro/1008.yaml","old_content":"color: D3\nexits:\n west:\n room: 1007\nid: 1008\nname: 'Room #1008'\n","new_content":"id: 1008\nname: 'Room #1008'\ncolor: D3\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"}]},{"time":"2026-07-14T01:27:59-04:00","description":"create room 1010","file_path":"data/rooms/intro/1010.yaml","old_content":"","new_content":"color: D3\nexits:\n east:\n room: 1009\nid: 1010\nname: 'Room #1010'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/intro/1009.yaml","old_content":"color: D3\nexits:\n south:\n room: 1008\nid: 1009\nname: 'Room #1009'\n","new_content":"id: 1009\nname: 'Room #1009'\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1008\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"}]},{"time":"2026-07-14T01:28:00-04:00","description":"create room 1011","file_path":"data/rooms/intro/1011.yaml","old_content":"","new_content":"color: D3\nexits:\n south:\n room: 1010\nid: 1011\nname: 'Room #1011'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/intro/1010.yaml","old_content":"color: D3\nexits:\n east:\n room: 1009\nid: 1010\nname: 'Room #1010'\n","new_content":"id: 1010\nname: 'Room #1010'\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"}]},{"time":"2026-07-14T01:28:00-04:00","description":"create room 1012","file_path":"data/rooms/intro/1012.yaml","old_content":"","new_content":"color: D3\nexits:\n west:\n room: 1011\nid: 1012\nname: 'Room #1012'\n","is_delete":false,"is_create":true,"extra_files":[{"file_path":"data/rooms/intro/1011.yaml","old_content":"color: D3\nexits:\n south:\n room: 1010\nid: 1011\nname: 'Room #1011'\n","new_content":"id: 1011\nname: 'Room #1011'\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1012\n south:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n"}]},{"time":"2026-07-14T01:28:08-04:00","description":"swap room 1008 with 1009 (north)","file_path":"data/rooms/intro/1008.yaml","old_content":"id: 1008\nname: 'Room #1008'\ncolor: D3\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1009'\nobjects: []\n","is_delete":false,"is_create":false,"extra_files":[{"file_path":"data/rooms/intro/1009.yaml","old_content":"id: 1009\nname: 'Room #1009'\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1008\n west:\n room: 1010\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1008\n west:\n room: 1010\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\n"}]},{"time":"2026-07-14T01:28:15-04:00","description":"swap room 1009 with 1008 (south)","file_path":"data/rooms/intro/1009.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1008\n west:\n room: 1010\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n south:\n room: 1008\n west:\n room: 1010\nhazard: \"\"\nid: 1009\nitem_spawns: []\nmobs: []\nname: 'Room #1009'\nobjects: []\n","is_delete":false,"is_create":false,"extra_files":[{"file_path":"data/rooms/intro/1008.yaml","old_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1009'\nobjects: []\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n north:\n room: 1009\n west:\n room: 1007\nhazard: \"\"\nid: 1008\nitem_spawns: []\nmobs: []\nname: 'Room #1008'\nobjects: []\n"}]},{"time":"2026-07-14T01:28:39-04:00","description":"update room 1010","file_path":"data/rooms/intro/1010.yaml","old_content":"id: 1010\nname: 'Room #1010'\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n north:\n room: 1011\nobjects: []\nitem_spawns: []\nmobs: []\nhazard: \"\"\nblock_transport: false\n","new_content":"block_transport: false\ncolor: D3\ndescription: []\nexits:\n east:\n room: 1009\n north:\n room: 1011\nhazard: \"\"\nid: 1010\nitem_spawns: []\nmobs: []\nname: 'Room #1009'\nobjects: []\n","is_delete":false,"is_create":false}],"redo":null} \ No newline at end of file diff --git a/data/techs/amplifier_1.yaml b/data/techs/amplifier_1.yaml index 6b47c9d..6de139d 100644 --- a/data/techs/amplifier_1.yaml +++ b/data/techs/amplifier_1.yaml @@ -1,7 +1,6 @@ name: Power Amplifier level: 7 drain_rate: 0.05 -category: strength group: strength_tier effects: strength_percent: 5 diff --git a/data/techs/amplifier_2.yaml b/data/techs/amplifier_2.yaml index 3a8950a..df362d4 100644 --- a/data/techs/amplifier_2.yaml +++ b/data/techs/amplifier_2.yaml @@ -1,7 +1,6 @@ name: Enhanced Amplifier level: 23 drain_rate: 0.10 -category: strength group: strength_tier effects: strength_percent: 10 diff --git a/data/techs/amplifier_3.yaml b/data/techs/amplifier_3.yaml index ff72433..c255c3a 100644 --- a/data/techs/amplifier_3.yaml +++ b/data/techs/amplifier_3.yaml @@ -1,7 +1,6 @@ name: Superior Amplifier level: 49 drain_rate: 0.15 -category: strength group: strength_tier effects: strength_percent: 15 diff --git a/data/techs/clarity_1.yaml b/data/techs/clarity_1.yaml index 47afa33..7e44f2a 100644 --- a/data/techs/clarity_1.yaml +++ b/data/techs/clarity_1.yaml @@ -1,7 +1,6 @@ name: Clarity level: 4 drain_rate: 0.05 -category: accuracy group: accuracy_tier effects: accuracy_percent: 5 diff --git a/data/techs/clarity_2.yaml b/data/techs/clarity_2.yaml index 9db17ed..d67b245 100644 --- a/data/techs/clarity_2.yaml +++ b/data/techs/clarity_2.yaml @@ -1,7 +1,6 @@ name: Enhanced Clarity level: 16 drain_rate: 0.10 -category: accuracy group: accuracy_tier effects: accuracy_percent: 10 diff --git a/data/techs/clarity_3.yaml b/data/techs/clarity_3.yaml index 6ab54f7..69c04c5 100644 --- a/data/techs/clarity_3.yaml +++ b/data/techs/clarity_3.yaml @@ -1,7 +1,6 @@ name: Superior Clarity level: 44 drain_rate: 0.15 -category: accuracy group: accuracy_tier effects: accuracy_percent: 15 diff --git a/data/techs/focus_1.yaml b/data/techs/focus_1.yaml index 07139c8..d509bc8 100644 --- a/data/techs/focus_1.yaml +++ b/data/techs/focus_1.yaml @@ -1,7 +1,6 @@ name: Neural Focus level: 9 drain_rate: 0.05 -category: science group: science_tier effects: science_percent: 5 diff --git a/data/techs/focus_2.yaml b/data/techs/focus_2.yaml index cbda53a..6513e36 100644 --- a/data/techs/focus_2.yaml +++ b/data/techs/focus_2.yaml @@ -1,7 +1,6 @@ name: Enhanced Focus level: 27 drain_rate: 0.10 -category: science group: science_tier effects: science_percent: 10 diff --git a/data/techs/focus_3.yaml b/data/techs/focus_3.yaml index 3f777bf..53f27e1 100644 --- a/data/techs/focus_3.yaml +++ b/data/techs/focus_3.yaml @@ -1,7 +1,6 @@ name: Superior Focus level: 55 drain_rate: 0.15 -category: science group: science_tier effects: science_percent: 15 diff --git a/data/techs/fortify.yaml b/data/techs/fortify.yaml index c7a3fcf..e3d0bc2 100644 --- a/data/techs/fortify.yaml +++ b/data/techs/fortify.yaml @@ -1,7 +1,6 @@ name: Fortify level: 65 drain_rate: 0.25 -category: combo group: defense_tier effects: defense_percent: 15 diff --git a/data/techs/overclock.yaml b/data/techs/overclock.yaml index 853365f..28982c8 100644 --- a/data/techs/overclock.yaml +++ b/data/techs/overclock.yaml @@ -1,7 +1,6 @@ name: Overclock level: 60 drain_rate: 0.25 -category: combo group: accuracy_tier effects: accuracy_percent: 15 diff --git a/data/techs/preserve.yaml b/data/techs/preserve.yaml index eec5e88..610354f 100644 --- a/data/techs/preserve.yaml +++ b/data/techs/preserve.yaml @@ -1,7 +1,6 @@ name: Power Saver level: 55 drain_rate: 0.05 -category: utility group: "" effects: preserve_drain: 0.2 diff --git a/data/techs/protect_melee.yaml b/data/techs/protect_melee.yaml index 730afcd..d4af9bc 100644 --- a/data/techs/protect_melee.yaml +++ b/data/techs/protect_melee.yaml @@ -1,7 +1,6 @@ name: Kinetic Barrier level: 37 drain_rate: 0.20 -category: protection group: protection effects: protect_melee: true diff --git a/data/techs/protect_ranged.yaml b/data/techs/protect_ranged.yaml index 2557af8..a3fb740 100644 --- a/data/techs/protect_ranged.yaml +++ b/data/techs/protect_ranged.yaml @@ -1,7 +1,6 @@ name: Projectile Screen level: 40 drain_rate: 0.20 -category: protection group: protection effects: protect_ranged: true diff --git a/data/techs/protect_science.yaml b/data/techs/protect_science.yaml index 8dc4e76..028123c 100644 --- a/data/techs/protect_science.yaml +++ b/data/techs/protect_science.yaml @@ -1,7 +1,6 @@ name: Neural Firewall level: 43 drain_rate: 0.20 -category: protection group: protection effects: protect_science: true diff --git a/data/techs/rapid_heal.yaml b/data/techs/rapid_heal.yaml index fe36c19..ed30096 100644 --- a/data/techs/rapid_heal.yaml +++ b/data/techs/rapid_heal.yaml @@ -1,7 +1,6 @@ name: Rapid Repair level: 31 drain_rate: 0.15 -category: utility group: regen_tier effects: hp_regen_multi: 4.0 diff --git a/data/techs/regen.yaml b/data/techs/regen.yaml index 94855b4..8aad259 100644 --- a/data/techs/regen.yaml +++ b/data/techs/regen.yaml @@ -1,7 +1,6 @@ name: Nano Repair level: 22 drain_rate: 0.10 -category: utility group: regen_tier effects: hp_regen_multi: 2.0 diff --git a/data/techs/retribution.yaml b/data/techs/retribution.yaml index a6350ee..8b3a771 100644 --- a/data/techs/retribution.yaml +++ b/data/techs/retribution.yaml @@ -1,7 +1,6 @@ name: Dead Man's Switch level: 46 drain_rate: 0.10 -category: utility group: "" effects: retribution_pct: 0.25 diff --git a/data/techs/shield_1.yaml b/data/techs/shield_1.yaml index 0a445c2..b1dff79 100644 --- a/data/techs/shield_1.yaml +++ b/data/techs/shield_1.yaml @@ -1,7 +1,6 @@ name: Energy Shield level: 10 drain_rate: 0.05 -category: defense group: defense_tier effects: defense_percent: 5 diff --git a/data/techs/shield_2.yaml b/data/techs/shield_2.yaml index bb55150..3eae4ec 100644 --- a/data/techs/shield_2.yaml +++ b/data/techs/shield_2.yaml @@ -1,7 +1,6 @@ name: Enhanced Shield level: 28 drain_rate: 0.10 -category: defense group: defense_tier effects: defense_percent: 10 diff --git a/data/techs/shield_3.yaml b/data/techs/shield_3.yaml index da1358f..63b9237 100644 --- a/data/techs/shield_3.yaml +++ b/data/techs/shield_3.yaml @@ -1,7 +1,6 @@ name: Superior Shield level: 52 drain_rate: 0.15 -category: defense group: defense_tier effects: defense_percent: 15 diff --git a/data/techs/targeting_1.yaml b/data/techs/targeting_1.yaml index 13a3cdb..2687aab 100644 --- a/data/techs/targeting_1.yaml +++ b/data/techs/targeting_1.yaml @@ -1,7 +1,6 @@ name: Targeting System level: 8 drain_rate: 0.05 -category: ranged group: ranged_tier effects: ranged_percent: 5 diff --git a/data/techs/targeting_2.yaml b/data/techs/targeting_2.yaml index 55eaf5e..50d602d 100644 --- a/data/techs/targeting_2.yaml +++ b/data/techs/targeting_2.yaml @@ -1,7 +1,6 @@ name: Enhanced Targeting level: 22 drain_rate: 0.10 -category: ranged group: ranged_tier effects: ranged_percent: 10 diff --git a/data/techs/targeting_3.yaml b/data/techs/targeting_3.yaml index 35017be..1272956 100644 --- a/data/techs/targeting_3.yaml +++ b/data/techs/targeting_3.yaml @@ -1,7 +1,6 @@ name: Superior Targeting level: 46 drain_rate: 0.15 -category: ranged group: ranged_tier effects: ranged_percent: 15 diff --git a/internal/admin/api_techs.go b/internal/admin/api_techs.go index 0d3e201..293b1db 100644 --- a/internal/admin/api_techs.go +++ b/internal/admin/api_techs.go @@ -7,6 +7,14 @@ import ( "strings" ) +func (s *AdminServer) findTechFile(id string) ([]byte, string, error) { + data, path, err := readYAMLFile(s.dataDir, "techs", id) + if err == nil { + return data, path, nil + } + return findYAMLFileInSubdirs(s.dataDir, "techs", id) +} + func (s *AdminServer) handleTechs(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: @@ -31,11 +39,11 @@ func (s *AdminServer) handleTechs(w http.ResponseWriter, r *http.Request) { return } delete(m, "id") - path := filepath.Join(s.dataDir, "techs", id+".yaml") - if _, err := os.Stat(path); err == nil { + if _, _, err := s.findTechFile(id); err == nil { writeJSON(w, map[string]any{"error": "tech already exists"}) return } + path := filepath.Join(s.dataDir, "techs", id+".yaml") newContent, err := writeMapAsYAML(path, m) if err != nil { writeJSON(w, map[string]any{"error": "write error: " + err.Error()}) @@ -62,7 +70,7 @@ func (s *AdminServer) handleTechByID(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: - data, path, err := findYAMLFileInSubdirs(s.dataDir, "techs", id) + data, path, err := s.findTechFile(id) if err != nil { writeJSON(w, map[string]any{"error": "not found: " + id}) return @@ -87,10 +95,17 @@ func (s *AdminServer) handleTechByID(w http.ResponseWriter, r *http.Request) { delete(body, "_path") delete(body, "_raw") - path := filepath.Join(s.dataDir, "techs", id+".yaml") + _, path, findErr := s.findTechFile(id) + isCreate := findErr != nil + if isCreate { + path = filepath.Join(s.dataDir, "techs", id+".yaml") + } + var oldContent []byte - if existing, err := snapshotFile(path); err == nil { - oldContent = existing + if !isCreate { + if existing, err := snapshotFile(path); err == nil { + oldContent = existing + } } newContent, err := writeMapAsYAML(path, body) @@ -99,7 +114,6 @@ func (s *AdminServer) handleTechByID(w http.ResponseWriter, r *http.Request) { return } - isCreate := oldContent == nil desc := "Updated tech " + id if isCreate { desc = "Created tech " + id @@ -114,7 +128,7 @@ func (s *AdminServer) handleTechByID(w http.ResponseWriter, r *http.Request) { writeJSON(w, map[string]any{"ok": true, "id": id}) case http.MethodDelete: - _, path, err := findYAMLFileInSubdirs(s.dataDir, "techs", id) + _, path, err := s.findTechFile(id) if err != nil { writeJSON(w, map[string]any{"error": "not found: " + id}) return diff --git a/internal/admin/static/admin.css b/internal/admin/static/admin.css index 3d54e54..8106773 100644 --- a/internal/admin/static/admin.css +++ b/internal/admin/static/admin.css @@ -146,6 +146,7 @@ input.search-input{padding-right:24px;background-image:url("data:image/svg+xml,% .talk-orphans{margin-top:12px;padding-top:8px;border-top:1px dashed var(--border)} .talk-orphans-label{font-size:10px;color:#f39c12;text-transform:uppercase;letter-spacing:.3px;margin-bottom:2px} .talk-orphans-hint{font-size:9px;color:#888;margin-bottom:6px;font-style:italic} +.tech-info-hint{font-size:10px;color:#888;margin-bottom:8px;font-style:italic} .tabs{display:flex;gap:2px;margin-bottom:12px;border-bottom:1px solid var(--border);padding-bottom:0} .tab{padding:6px 14px;font-size:12px;background:transparent;color:#aaa;border:none;border-bottom:2px solid transparent;cursor:pointer;font-family:monospace} .tab:hover{color:var(--text)} diff --git a/internal/admin/static/techeditor.js b/internal/admin/static/techeditor.js index 020ba11..27dcbd8 100644 --- a/internal/admin/static/techeditor.js +++ b/internal/admin/static/techeditor.js @@ -10,8 +10,7 @@ var TECH_SECTIONS = [ ['name', 'Name', 'text', 'Protect from Melee'], ['level', 'Level', 'number', '37', 'narrow'], ['drain_rate', 'Drain Rate', 'number', '0.5', 'narrow'], - ['category', 'Category', 'select', '|accuracy|combo|defense|protection|ranged|science|strength|utility'], - ['group', 'Group', 'select', '|accuracy_tier|defense_tier|protection|ranged_tier|regen_tier|science_tier|strength_tier'], + ['group', 'Group', 'text', 'accuracy_tier'], ] }, { @@ -26,9 +25,6 @@ var TECH_SECTIONS = [ ['hp_regen_multi', 'HP Regen Multi', 'number', '2', 'narrow'], ['preserve_drain', 'Preserve Drain', 'number', '1', 'narrow'], ['retribution_pct', 'Retribution %', 'number', '25', 'narrow'], - ['protect_melee', 'Protect Melee', 'checkbox'], - ['protect_ranged', 'Protect Ranged', 'checkbox'], - ['protect_science', 'Protect Science', 'checkbox'], ] } ]; @@ -118,18 +114,26 @@ function renderCard(sec, data) { h += ''; h += ''; h += '