mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-25 23:25:43 -03:00
refactor: move supporters loading to separate API endpoint
- Add SupportersHandler in misc_handlers.py to serve /api/lm/supporters - Register new endpoint in misc_route_registrar.py - Remove supporters from page load template context in model_handlers.py - Create supportersService.js for frontend data fetching - Update Header.js to fetch supporters when support modal opens - Modify support_modal.html to use client-side rendering This change improves page load performance by loading supporters data on-demand instead of during initial page render.
This commit is contained in:
621
data/supporters.json
Normal file
621
data/supporters.json
Normal file
@@ -0,0 +1,621 @@
|
|||||||
|
{
|
||||||
|
"specialThanks": [
|
||||||
|
"dispenser",
|
||||||
|
"EbonEagle",
|
||||||
|
"DanielMagPizza",
|
||||||
|
"Scott R"
|
||||||
|
],
|
||||||
|
"allSupporters": [
|
||||||
|
"megakirbs",
|
||||||
|
"Brennok",
|
||||||
|
"Christian Byrne",
|
||||||
|
"wackop",
|
||||||
|
"Insomnia Art Designs",
|
||||||
|
"2018cfh",
|
||||||
|
"Takkan",
|
||||||
|
"$MetaSamsara",
|
||||||
|
"onesecondinosaur",
|
||||||
|
"stone9k",
|
||||||
|
"Francisco Tatis",
|
||||||
|
"FreelancerZ",
|
||||||
|
"Gooohokrbe",
|
||||||
|
"JongWon Han",
|
||||||
|
"OldBones",
|
||||||
|
"Rosenthal",
|
||||||
|
"runte3221",
|
||||||
|
"Birdy",
|
||||||
|
"Fraser Cross",
|
||||||
|
"Polymorphic Indeterminate",
|
||||||
|
"Marc Whiffen",
|
||||||
|
"Kiba",
|
||||||
|
"Jorge Hussni",
|
||||||
|
"Reno Lam",
|
||||||
|
"Skalabananen",
|
||||||
|
"esthe",
|
||||||
|
"sig",
|
||||||
|
"DM",
|
||||||
|
"Sen314",
|
||||||
|
"Estragon",
|
||||||
|
"J\\B/ 8r0wns0n",
|
||||||
|
"Andrew Wilson",
|
||||||
|
"Buzzard",
|
||||||
|
"carozzz",
|
||||||
|
"ClockDaemon",
|
||||||
|
"Cosmosis",
|
||||||
|
"Echo",
|
||||||
|
"Edgar Tejeda",
|
||||||
|
"FloPro4Sho",
|
||||||
|
"fnkylove",
|
||||||
|
"Greybush",
|
||||||
|
"iamresist",
|
||||||
|
"Illrigger",
|
||||||
|
"JackieWang",
|
||||||
|
"James Dooley",
|
||||||
|
"James Todd",
|
||||||
|
"jmack",
|
||||||
|
"Julian V",
|
||||||
|
"KD",
|
||||||
|
"lh qwe",
|
||||||
|
"Lilleman",
|
||||||
|
"Lisster",
|
||||||
|
"Mark Corneglio",
|
||||||
|
"Michael Wong",
|
||||||
|
"Omnidex",
|
||||||
|
"PM",
|
||||||
|
"Release Cabrakan",
|
||||||
|
"Ricky Carter",
|
||||||
|
"Robert Stacey",
|
||||||
|
"SarcasticHashtag",
|
||||||
|
"SG",
|
||||||
|
"Steven Owens",
|
||||||
|
"tarek helmi",
|
||||||
|
"Tee Gee",
|
||||||
|
"Tim",
|
||||||
|
"Tobi_Swagg",
|
||||||
|
"Todd Keck",
|
||||||
|
"Tom Corrigan",
|
||||||
|
"VantAI",
|
||||||
|
"Vik71it",
|
||||||
|
"Wolffen",
|
||||||
|
"Yushio",
|
||||||
|
"zenbound",
|
||||||
|
"itismyelement",
|
||||||
|
"Mozzel",
|
||||||
|
"Gingko Biloba",
|
||||||
|
"Penfore",
|
||||||
|
"BadassArabianMofo",
|
||||||
|
"Liam MacDougal",
|
||||||
|
"Sterilized",
|
||||||
|
"Markus",
|
||||||
|
"quarz",
|
||||||
|
"Greg",
|
||||||
|
"Douglas Gaspar",
|
||||||
|
"JSST",
|
||||||
|
"AlexDuKaNa",
|
||||||
|
"Snaggwort",
|
||||||
|
"George",
|
||||||
|
"lmsupporter@fastmail.de",
|
||||||
|
"Phil",
|
||||||
|
"Carl G.",
|
||||||
|
"Arlecchino Shion",
|
||||||
|
"Charles Blakemore",
|
||||||
|
"IamAyam",
|
||||||
|
"wfpearl",
|
||||||
|
"Rob Williams",
|
||||||
|
"Aaron Bleuer",
|
||||||
|
"Adam Shaw",
|
||||||
|
"Alex",
|
||||||
|
"Anthony Rizzo",
|
||||||
|
"ASLPro3D",
|
||||||
|
"Baekdoosixt",
|
||||||
|
"bh",
|
||||||
|
"Big Red",
|
||||||
|
"Bishoujoker",
|
||||||
|
"Briton Heilbrun",
|
||||||
|
"confiscated Zyra",
|
||||||
|
"conner",
|
||||||
|
"contrite831",
|
||||||
|
"corde",
|
||||||
|
"Cory Paza",
|
||||||
|
"CryptoTraderJK",
|
||||||
|
"daniel dove",
|
||||||
|
"David Ortega",
|
||||||
|
"dl0901dm",
|
||||||
|
"FinalyFree",
|
||||||
|
"Graham Colehour",
|
||||||
|
"Jack B Nimble",
|
||||||
|
"Jacob Hoehler",
|
||||||
|
"Johnny",
|
||||||
|
"Jonathan Ross",
|
||||||
|
"JW Sin",
|
||||||
|
"LacesOut!",
|
||||||
|
"Luc Job",
|
||||||
|
"Lustre",
|
||||||
|
"Marlon Daniels",
|
||||||
|
"Melville Parrish",
|
||||||
|
"Nazono_hito",
|
||||||
|
"Nick Walker",
|
||||||
|
"Philip Hempel",
|
||||||
|
"Princess Bright Eyes",
|
||||||
|
"RedrockVP",
|
||||||
|
"Starkselle",
|
||||||
|
"Steven Pfeiffer",
|
||||||
|
"Tak",
|
||||||
|
"Timmy",
|
||||||
|
"Tomohiro Baba",
|
||||||
|
"Tori",
|
||||||
|
"Tyler Trebuchon",
|
||||||
|
"Weasyl",
|
||||||
|
"whudunit",
|
||||||
|
"wildnut",
|
||||||
|
"Yaboi",
|
||||||
|
"Zach Gonser",
|
||||||
|
"Davaitamin",
|
||||||
|
"Felipe dos Santos",
|
||||||
|
"Aleksander Wujczyk",
|
||||||
|
"AM Kuro",
|
||||||
|
"jean jahren",
|
||||||
|
"tedcor",
|
||||||
|
"Pascal Dahle",
|
||||||
|
"S Sang",
|
||||||
|
"MagnaInsomnia",
|
||||||
|
"Akira_HentAI",
|
||||||
|
"Karl P.",
|
||||||
|
"Gordon Cole",
|
||||||
|
"yuxz69",
|
||||||
|
"MadSpin",
|
||||||
|
"[anonymous]",
|
||||||
|
"dw",
|
||||||
|
"N/A",
|
||||||
|
"The Spawn",
|
||||||
|
"graysock",
|
||||||
|
"Greenmoustache",
|
||||||
|
"Gamalonia",
|
||||||
|
"fancypants",
|
||||||
|
"Vir",
|
||||||
|
"aai",
|
||||||
|
"AELOX",
|
||||||
|
"Anthony Faxlandez",
|
||||||
|
"ApathyJones",
|
||||||
|
"Aquatic Coffee",
|
||||||
|
"batblue",
|
||||||
|
"carey6409",
|
||||||
|
"Christopher Michel",
|
||||||
|
"Damon Cunliffe",
|
||||||
|
"dan",
|
||||||
|
"Digital",
|
||||||
|
"Dogmaster",
|
||||||
|
"Draven T",
|
||||||
|
"drum matthieu",
|
||||||
|
"Dustin Chen",
|
||||||
|
"ethanfel",
|
||||||
|
"Focuschannel",
|
||||||
|
"Gonzalo Andre Allendes Lopez",
|
||||||
|
"JaxMax",
|
||||||
|
"Jimmy Ledbetter",
|
||||||
|
"John Saveas",
|
||||||
|
"Jwk0205",
|
||||||
|
"LeoZero",
|
||||||
|
"Lex Song",
|
||||||
|
"M Postkasse",
|
||||||
|
"Matt Wenzel",
|
||||||
|
"Mattssn",
|
||||||
|
"Max Marklund",
|
||||||
|
"Mouthlessman",
|
||||||
|
"nahinahi9",
|
||||||
|
"Nicfit23",
|
||||||
|
"Noora",
|
||||||
|
"Olive",
|
||||||
|
"Serge Bekenkamp",
|
||||||
|
"Seth Christensen",
|
||||||
|
"Some Guy Named Barry",
|
||||||
|
"Steam Steam",
|
||||||
|
"takyamtom",
|
||||||
|
"ViperC",
|
||||||
|
"wamekukyouzin",
|
||||||
|
"奚明 刘",
|
||||||
|
"otaku fra",
|
||||||
|
"AbstractAss",
|
||||||
|
"semicolon drainpipe",
|
||||||
|
"Ran C",
|
||||||
|
"Thesharingbrother",
|
||||||
|
"Fotek Design",
|
||||||
|
"ResidentDeviant",
|
||||||
|
"Adam Taylor",
|
||||||
|
"JC",
|
||||||
|
"Weird_With_A_Beard",
|
||||||
|
"Prompt Pirate",
|
||||||
|
"Pozadine1",
|
||||||
|
"uwutismxd",
|
||||||
|
"Qarob",
|
||||||
|
"AIGooner",
|
||||||
|
"inbijiburu",
|
||||||
|
"decoy",
|
||||||
|
"Luc",
|
||||||
|
"ProtonPrince",
|
||||||
|
"DiffDuck",
|
||||||
|
"elu3199",
|
||||||
|
"Nick “Loadstone” D",
|
||||||
|
"Hasturkun",
|
||||||
|
"Jon Sandman",
|
||||||
|
"Ubivis",
|
||||||
|
"zounic",
|
||||||
|
"CloudValley",
|
||||||
|
"linnfrey",
|
||||||
|
"zenobeus",
|
||||||
|
"Jackthemind",
|
||||||
|
"Stryker",
|
||||||
|
"Pkrsky",
|
||||||
|
"raf8osz5",
|
||||||
|
"Antonio Pontes",
|
||||||
|
"aRtFuL_DodGeR",
|
||||||
|
"Billy Gladky",
|
||||||
|
"Blackfish95",
|
||||||
|
"blikkies",
|
||||||
|
"Bohemian Corporal",
|
||||||
|
"Bro Xie",
|
||||||
|
"Bruce",
|
||||||
|
"CrimsonDX",
|
||||||
|
"Cristian Vazquez",
|
||||||
|
"Dan",
|
||||||
|
"Dankin",
|
||||||
|
"DarkSunset",
|
||||||
|
"dd",
|
||||||
|
"DougPeterson",
|
||||||
|
"Error_Rule34_Not_found",
|
||||||
|
"Frank Nitty",
|
||||||
|
"Goldwaters",
|
||||||
|
"Griffin Dahlberg",
|
||||||
|
"jinxedx",
|
||||||
|
"Joboshy",
|
||||||
|
"Kevin Christopher",
|
||||||
|
"Kevin John Duck",
|
||||||
|
"Kyler",
|
||||||
|
"Magic Noob",
|
||||||
|
"Neco28",
|
||||||
|
"Ouro Boros",
|
||||||
|
"Paul Kroll",
|
||||||
|
"Probis",
|
||||||
|
"Roslynd",
|
||||||
|
"Shock Shockor",
|
||||||
|
"Spitfire_502",
|
||||||
|
"X",
|
||||||
|
"yer fey",
|
||||||
|
"Zude",
|
||||||
|
"太郎 ゲーム",
|
||||||
|
"준희 김",
|
||||||
|
"shrshpp",
|
||||||
|
"ItsGeneralButtNaked",
|
||||||
|
"John Statham",
|
||||||
|
"Nimess",
|
||||||
|
"Bas Imagineer",
|
||||||
|
"Pat Hen",
|
||||||
|
"Youguang",
|
||||||
|
"andrewzpong",
|
||||||
|
"FrxzenSnxw",
|
||||||
|
"BossGame",
|
||||||
|
"thesoftwaredruid",
|
||||||
|
"wundershark",
|
||||||
|
"mr_dinosaur",
|
||||||
|
"Tyrswood",
|
||||||
|
"Ray Wing",
|
||||||
|
"Ranzitho",
|
||||||
|
"Gus",
|
||||||
|
"地獄の禄",
|
||||||
|
"MJG",
|
||||||
|
"David LaVallee",
|
||||||
|
"ae",
|
||||||
|
"Tr4shP4nda",
|
||||||
|
"WRL_SPR",
|
||||||
|
"capn",
|
||||||
|
"Joseph",
|
||||||
|
"anonymousoddity",
|
||||||
|
"Mirko Katzula",
|
||||||
|
"dan",
|
||||||
|
"Piccio08",
|
||||||
|
"kumakichi",
|
||||||
|
"a _",
|
||||||
|
"aezin",
|
||||||
|
"battu",
|
||||||
|
"Brian M",
|
||||||
|
"Chad Idk",
|
||||||
|
"Chris",
|
||||||
|
"Emil Andersson",
|
||||||
|
"Emil Bernhoff",
|
||||||
|
"Erik Lopez",
|
||||||
|
"Eris3D",
|
||||||
|
"Geolog",
|
||||||
|
"Gerald Welly",
|
||||||
|
"Haru Yotu",
|
||||||
|
"James Coleman",
|
||||||
|
"Jamie Ogletree",
|
||||||
|
"jcay015",
|
||||||
|
"Jeff",
|
||||||
|
"John Martin",
|
||||||
|
"Josef Lanzl",
|
||||||
|
"Kevin Picco",
|
||||||
|
"m",
|
||||||
|
"Martial",
|
||||||
|
"Mateo Curić",
|
||||||
|
"Matura Arbeit",
|
||||||
|
"Michael Docherty",
|
||||||
|
"moranqianlong",
|
||||||
|
"Nerezza",
|
||||||
|
"Pierce McBride",
|
||||||
|
"sanborondon",
|
||||||
|
"SendingRavens",
|
||||||
|
"Taylor Funk",
|
||||||
|
"TBitz33",
|
||||||
|
"Thought2Form",
|
||||||
|
"Yuji Kaneko",
|
||||||
|
"elitassj4",
|
||||||
|
"Dušan Ryban",
|
||||||
|
"Jacob Winter",
|
||||||
|
"Jordan Shaw",
|
||||||
|
"Sam",
|
||||||
|
"Rops Alot",
|
||||||
|
"SRDB",
|
||||||
|
"sjon kreutz",
|
||||||
|
"g unit",
|
||||||
|
"Ace Ventura",
|
||||||
|
"David",
|
||||||
|
"Meilo",
|
||||||
|
"Nihongasuki",
|
||||||
|
"Pen Bouryoung",
|
||||||
|
"shinonomeiro",
|
||||||
|
"Snille",
|
||||||
|
"Metryman55",
|
||||||
|
"MaartenAlbers",
|
||||||
|
"khanh duy",
|
||||||
|
"xybrightsummer",
|
||||||
|
"ColdBread",
|
||||||
|
"PhilW",
|
||||||
|
"momokai",
|
||||||
|
"cppbel",
|
||||||
|
"starbugx",
|
||||||
|
"Janik",
|
||||||
|
"Moon Knight",
|
||||||
|
"몽타주",
|
||||||
|
"Kland",
|
||||||
|
"Hailshem",
|
||||||
|
"kudari",
|
||||||
|
"Naomi Hale Danchi",
|
||||||
|
"dc7431",
|
||||||
|
"ken",
|
||||||
|
"Inversity",
|
||||||
|
"Crocket",
|
||||||
|
"AIVORY3D",
|
||||||
|
"epicgamer0020690",
|
||||||
|
"Joshua Porrata",
|
||||||
|
"Cruel",
|
||||||
|
"keemun",
|
||||||
|
"SuBu",
|
||||||
|
"RedPIXel",
|
||||||
|
"MRBlack",
|
||||||
|
"Kevinj",
|
||||||
|
"Wind",
|
||||||
|
"Nexus",
|
||||||
|
"Mitchell Robson",
|
||||||
|
"Ramneek“Guy”Ashok",
|
||||||
|
"squid_actually",
|
||||||
|
"Nat_20",
|
||||||
|
"Kiyoe",
|
||||||
|
"Edward Weeks",
|
||||||
|
"kyoumei",
|
||||||
|
"RadStorm04",
|
||||||
|
"JohnDoe42054",
|
||||||
|
"BillyHill",
|
||||||
|
"humptynutz",
|
||||||
|
"emyth",
|
||||||
|
"Kalnei",
|
||||||
|
"ryoma7612",
|
||||||
|
"ResidentDeviant",
|
||||||
|
"Scott",
|
||||||
|
"gzmzmvp",
|
||||||
|
"Aeternyx",
|
||||||
|
"ahoystan",
|
||||||
|
"Andrew",
|
||||||
|
"Artokun",
|
||||||
|
"Atilla Berke Pekduyar",
|
||||||
|
"Bob Barker",
|
||||||
|
"Brian Buie",
|
||||||
|
"Decx _",
|
||||||
|
"Derek Baker",
|
||||||
|
"Doug Mason",
|
||||||
|
"Eric Whitney",
|
||||||
|
"hayden",
|
||||||
|
"Ivan Tadic",
|
||||||
|
"ja s",
|
||||||
|
"Jack Dole",
|
||||||
|
"Jacob McDaniel",
|
||||||
|
"Jeremy Townsend",
|
||||||
|
"Joey Callahan",
|
||||||
|
"Joshua Gray",
|
||||||
|
"kevin stoddard",
|
||||||
|
"Kevin Wallace",
|
||||||
|
"Kyron Mahan",
|
||||||
|
"Leland Saunders",
|
||||||
|
"Littlehuggy",
|
||||||
|
"Maso",
|
||||||
|
"Matheus Couto",
|
||||||
|
"Michael Anthony Scott",
|
||||||
|
"Michael Taylor",
|
||||||
|
"Mike Simone",
|
||||||
|
"Mikko Hemilä",
|
||||||
|
"Morgandel",
|
||||||
|
"mrjuan",
|
||||||
|
"Noah",
|
||||||
|
"Owen Gwosdz",
|
||||||
|
"Richard",
|
||||||
|
"Robert Wegemund",
|
||||||
|
"Sadlip",
|
||||||
|
"Sean voets",
|
||||||
|
"Sloan Steddy",
|
||||||
|
"Temikus",
|
||||||
|
"Thomas Wanner",
|
||||||
|
"y2Rxy7FdXzWo",
|
||||||
|
"YOU SINWOO",
|
||||||
|
"Paul Hartsuyker",
|
||||||
|
"ChicRic",
|
||||||
|
"mercur2002",
|
||||||
|
"J C",
|
||||||
|
"Distortik",
|
||||||
|
"Yves Poezevara",
|
||||||
|
"Teriak47",
|
||||||
|
"Just me",
|
||||||
|
"Raf Stahelin",
|
||||||
|
"Вячеслав Маринин",
|
||||||
|
"Cola Matthew",
|
||||||
|
"OniNoKen",
|
||||||
|
"Iain Wisely",
|
||||||
|
"Zertens",
|
||||||
|
"NOHOW",
|
||||||
|
"Apo",
|
||||||
|
"nekotxt",
|
||||||
|
"choowkee",
|
||||||
|
"Clusters",
|
||||||
|
"ibrahim",
|
||||||
|
"Highlandrise",
|
||||||
|
"philcoraz",
|
||||||
|
"mztn11",
|
||||||
|
"ImagineerNL",
|
||||||
|
"MrAcrtosSursus",
|
||||||
|
"al300680",
|
||||||
|
"pixl",
|
||||||
|
"Robin",
|
||||||
|
"chahknoir@gmail.com",
|
||||||
|
"Marcus thronico",
|
||||||
|
"nd01",
|
||||||
|
"keno94d",
|
||||||
|
"James Melzer",
|
||||||
|
"Bartleby",
|
||||||
|
"Renvertere",
|
||||||
|
"Rahuy",
|
||||||
|
"Hermann003",
|
||||||
|
"D",
|
||||||
|
"Foolish",
|
||||||
|
"RevyHiep",
|
||||||
|
"Captain_Swag",
|
||||||
|
"obkircher",
|
||||||
|
"Tree Tagger",
|
||||||
|
"gwyar",
|
||||||
|
"Coeur de cochon",
|
||||||
|
"D",
|
||||||
|
"edgecase",
|
||||||
|
"Neoxena",
|
||||||
|
"mrmhalo",
|
||||||
|
"michael.isaza1",
|
||||||
|
"chriphost",
|
||||||
|
"KitKatM",
|
||||||
|
"socrasteeze",
|
||||||
|
"dg",
|
||||||
|
"Whitepinetrader",
|
||||||
|
"Maarten Harms",
|
||||||
|
"OrganicArtifact",
|
||||||
|
"四糸凜音",
|
||||||
|
"MudkipMedkitz",
|
||||||
|
"Israel",
|
||||||
|
"deanbrian",
|
||||||
|
"POPPIN",
|
||||||
|
"Muratoraccio",
|
||||||
|
"SelfishMedic",
|
||||||
|
"Ginnie",
|
||||||
|
"Alex Wortman",
|
||||||
|
"Cody",
|
||||||
|
"adderleighn",
|
||||||
|
"Raku",
|
||||||
|
"smart.edge5178",
|
||||||
|
"emadsultan",
|
||||||
|
"InformedViewz",
|
||||||
|
"CHKeeho80",
|
||||||
|
"Bubbafett",
|
||||||
|
"leaf",
|
||||||
|
"Menard",
|
||||||
|
"Skyfire83",
|
||||||
|
"Adam Rinehart",
|
||||||
|
"D",
|
||||||
|
"Pitpe11",
|
||||||
|
"TheD1rtyD03",
|
||||||
|
"EnragedAntelope",
|
||||||
|
"moonpetal",
|
||||||
|
"SomeDude",
|
||||||
|
"g9p0o",
|
||||||
|
"nanana",
|
||||||
|
"TheHolySheep",
|
||||||
|
"Monte Won",
|
||||||
|
"SpringBootisTrash",
|
||||||
|
"carsten",
|
||||||
|
"ikok",
|
||||||
|
"_ G3n",
|
||||||
|
"ACTUALLY_the_Real_Willem_Dafoe",
|
||||||
|
"Adictedtohumping",
|
||||||
|
"AllTimeNoobie",
|
||||||
|
"Banana Joe",
|
||||||
|
"beersandbacon",
|
||||||
|
"Chad Barnes",
|
||||||
|
"Chase Kwon",
|
||||||
|
"CptNeo",
|
||||||
|
"Devil Lude",
|
||||||
|
"Dismem",
|
||||||
|
"Donovan Jenkins",
|
||||||
|
"edk",
|
||||||
|
"Edward Kennedy",
|
||||||
|
"elleshar666",
|
||||||
|
"Elliot E",
|
||||||
|
"EpicElric",
|
||||||
|
"Eric Ketchum",
|
||||||
|
"Ezokewn",
|
||||||
|
"Forbidden Atelier",
|
||||||
|
"giani kidd",
|
||||||
|
"gonzalo",
|
||||||
|
"Goober719",
|
||||||
|
"Gregory Kozhemiak",
|
||||||
|
"han b",
|
||||||
|
"hexxish",
|
||||||
|
"Ink Temptation",
|
||||||
|
"Invis",
|
||||||
|
"james",
|
||||||
|
"Jean-françois SEMA",
|
||||||
|
"John C",
|
||||||
|
"John J Linehan",
|
||||||
|
"jumpd",
|
||||||
|
"Justin Blaylock",
|
||||||
|
"Justin Houston",
|
||||||
|
"Kalli Core",
|
||||||
|
"Kauffy",
|
||||||
|
"Kurt",
|
||||||
|
"Maximilian Pyko",
|
||||||
|
"Mewtora",
|
||||||
|
"Michael Eid",
|
||||||
|
"Michael Scott",
|
||||||
|
"Michael Zhu",
|
||||||
|
"Middo",
|
||||||
|
"Nathan",
|
||||||
|
"Nathan lee",
|
||||||
|
"NICHOLAS BAXLEY",
|
||||||
|
"Nico",
|
||||||
|
"notedfakes",
|
||||||
|
"OrochiNights",
|
||||||
|
"psytrax",
|
||||||
|
"Rim",
|
||||||
|
"Seraphy",
|
||||||
|
"Theerat Jiramate",
|
||||||
|
"Towelie",
|
||||||
|
"Vane Holzer",
|
||||||
|
"Wolfe7D1",
|
||||||
|
"Xan Dionysus",
|
||||||
|
"雨の心 落",
|
||||||
|
"James Ming",
|
||||||
|
"vanditking",
|
||||||
|
"kripitonga",
|
||||||
|
"Rizzi",
|
||||||
|
"nimin",
|
||||||
|
"OMAR LUCIANO",
|
||||||
|
"BrentBertram",
|
||||||
|
"eumelzocker",
|
||||||
|
"dxjaymz",
|
||||||
|
"L C",
|
||||||
|
"Dude"
|
||||||
|
],
|
||||||
|
"totalCount": 614
|
||||||
|
}
|
||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "WeChat QR-Code anzeigen",
|
"showWechatQR": "WeChat QR-Code anzeigen",
|
||||||
"hideWechatQR": "WeChat QR-Code ausblenden"
|
"hideWechatQR": "WeChat QR-Code ausblenden"
|
||||||
},
|
},
|
||||||
"footer": "Vielen Dank, dass Sie LoRA Manager verwenden! ❤️"
|
"footer": "Vielen Dank, dass Sie LoRA Manager verwenden! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "Danke an alle Unterstützer",
|
||||||
|
"subtitle": "Danke an {count} Unterstützer, die dieses Projekt möglich gemacht haben",
|
||||||
|
"specialThanks": "Besonderer Dank",
|
||||||
|
"allSupporters": "Alle Unterstützer",
|
||||||
|
"totalCount": "{count} Unterstützer insgesamt"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "Show WeChat QR Code",
|
"showWechatQR": "Show WeChat QR Code",
|
||||||
"hideWechatQR": "Hide WeChat QR Code"
|
"hideWechatQR": "Hide WeChat QR Code"
|
||||||
},
|
},
|
||||||
"footer": "Thank you for using LoRA Manager! ❤️"
|
"footer": "Thank you for using LoRA Manager! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "Thank You To Our Supporters",
|
||||||
|
"subtitle": "Thanks to {count} supporters who made this project possible",
|
||||||
|
"specialThanks": "Special Thanks",
|
||||||
|
"allSupporters": "All Supporters",
|
||||||
|
"totalCount": "{count} supporters in total"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "Mostrar código QR de WeChat",
|
"showWechatQR": "Mostrar código QR de WeChat",
|
||||||
"hideWechatQR": "Ocultar código QR de WeChat"
|
"hideWechatQR": "Ocultar código QR de WeChat"
|
||||||
},
|
},
|
||||||
"footer": "¡Gracias por usar el gestor de LoRA! ❤️"
|
"footer": "¡Gracias por usar el gestor de LoRA! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "Gracias a todos los seguidores",
|
||||||
|
"subtitle": "Gracias a {count} seguidores que hicieron este proyecto posible",
|
||||||
|
"specialThanks": "Agradecimientos especiales",
|
||||||
|
"allSupporters": "Todos los seguidores",
|
||||||
|
"totalCount": "{count} seguidores en total"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "Afficher le QR Code WeChat",
|
"showWechatQR": "Afficher le QR Code WeChat",
|
||||||
"hideWechatQR": "Masquer le QR Code WeChat"
|
"hideWechatQR": "Masquer le QR Code WeChat"
|
||||||
},
|
},
|
||||||
"footer": "Merci d'utiliser le Gestionnaire LoRA ! ❤️"
|
"footer": "Merci d'utiliser le Gestionnaire LoRA ! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "Merci à tous les supporters",
|
||||||
|
"subtitle": "Merci aux {count} supporters qui ont rendu ce projet possible",
|
||||||
|
"specialThanks": "Remerciements spéciaux",
|
||||||
|
"allSupporters": "Tous les supporters",
|
||||||
|
"totalCount": "{count} supporters au total"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "הצג קוד QR של WeChat",
|
"showWechatQR": "הצג קוד QR של WeChat",
|
||||||
"hideWechatQR": "הסתר קוד QR של WeChat"
|
"hideWechatQR": "הסתר קוד QR של WeChat"
|
||||||
},
|
},
|
||||||
"footer": "תודה על השימוש במנהל LoRA! ❤️"
|
"footer": "תודה על השימוש במנהל LoRA! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "תודה לכל התומכים",
|
||||||
|
"subtitle": "תודה ל־{count} תומכים שהפכו את הפרויקט הזה לאפשרי",
|
||||||
|
"specialThanks": "תודה מיוחדת",
|
||||||
|
"allSupporters": "כל התומכים",
|
||||||
|
"totalCount": "{count} תומכים בסך הכל"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "WeChat QRコードを表示",
|
"showWechatQR": "WeChat QRコードを表示",
|
||||||
"hideWechatQR": "WeChat QRコードを非表示"
|
"hideWechatQR": "WeChat QRコードを非表示"
|
||||||
},
|
},
|
||||||
"footer": "LoRA Managerをご利用いただきありがとうございます! ❤️"
|
"footer": "LoRA Managerをご利用いただきありがとうございます! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "サポーターの皆様に感謝",
|
||||||
|
"subtitle": "{count} 名のサポーターの皆様に、このプロジェクトを実現していただきありがとうございます",
|
||||||
|
"specialThanks": "特別感謝",
|
||||||
|
"allSupporters": "全サポーター",
|
||||||
|
"totalCount": "サポーター {count} 名"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "WeChat QR 코드 표시",
|
"showWechatQR": "WeChat QR 코드 표시",
|
||||||
"hideWechatQR": "WeChat QR 코드 숨기기"
|
"hideWechatQR": "WeChat QR 코드 숨기기"
|
||||||
},
|
},
|
||||||
"footer": "LoRA Manager를 사용해주셔서 감사합니다! ❤️"
|
"footer": "LoRA Manager를 사용해주셔서 감사합니다! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "후원자 분들께 감사드립니다",
|
||||||
|
"subtitle": "이 프로젝트를 가능하게 해준 {count}명의 후원자분들께 감사드립니다",
|
||||||
|
"specialThanks": "특별 감사",
|
||||||
|
"allSupporters": "모든 후원자",
|
||||||
|
"totalCount": "총 {count}명의 후원자"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "Показать QR-код WeChat",
|
"showWechatQR": "Показать QR-код WeChat",
|
||||||
"hideWechatQR": "Скрыть QR-код WeChat"
|
"hideWechatQR": "Скрыть QR-код WeChat"
|
||||||
},
|
},
|
||||||
"footer": "Спасибо за использование LoRA Manager! ❤️"
|
"footer": "Спасибо за использование LoRA Manager! ❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "Спасибо всем сторонникам",
|
||||||
|
"subtitle": "Спасибо {count} сторонникам, которые сделали этот проект возможным",
|
||||||
|
"specialThanks": "Особая благодарность",
|
||||||
|
"allSupporters": "Все сторонники",
|
||||||
|
"totalCount": "Всего {count} сторонников"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "显示微信二维码",
|
"showWechatQR": "显示微信二维码",
|
||||||
"hideWechatQR": "隐藏微信二维码"
|
"hideWechatQR": "隐藏微信二维码"
|
||||||
},
|
},
|
||||||
"footer": "感谢使用 LoRA 管理器!❤️"
|
"footer": "感谢使用 LoRA 管理器!❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "感谢所有支持者",
|
||||||
|
"subtitle": "感谢 {count} 位支持者让这个项目成为可能",
|
||||||
|
"specialThanks": "特别感谢",
|
||||||
|
"allSupporters": "所有支持者",
|
||||||
|
"totalCount": "共 {count} 位支持者"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -1342,7 +1342,14 @@
|
|||||||
"showWechatQR": "顯示微信二維碼",
|
"showWechatQR": "顯示微信二維碼",
|
||||||
"hideWechatQR": "隱藏微信二維碼"
|
"hideWechatQR": "隱藏微信二維碼"
|
||||||
},
|
},
|
||||||
"footer": "感謝您使用 LoRA 管理器!❤️"
|
"footer": "感謝您使用 LoRA 管理器!❤️",
|
||||||
|
"supporters": {
|
||||||
|
"title": "感謝所有支持者",
|
||||||
|
"subtitle": "感謝 {count} 位支持者讓這個專案成為可能",
|
||||||
|
"specialThanks": "特別感謝",
|
||||||
|
"allSupporters": "所有支持者",
|
||||||
|
"totalCount": "共 {count} 位支持者"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
"general": {
|
"general": {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ objects that can be composed by the route controller.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -218,6 +219,45 @@ class HealthCheckHandler:
|
|||||||
return web.json_response({"status": "ok"})
|
return web.json_response({"status": "ok"})
|
||||||
|
|
||||||
|
|
||||||
|
class SupportersHandler:
|
||||||
|
"""Handler for supporters data."""
|
||||||
|
|
||||||
|
def __init__(self, logger: logging.Logger | None = None) -> None:
|
||||||
|
self._logger = logger or logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def _load_supporters(self) -> dict:
|
||||||
|
"""Load supporters data from JSON file."""
|
||||||
|
try:
|
||||||
|
current_file = os.path.abspath(__file__)
|
||||||
|
root_dir = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(current_file)))
|
||||||
|
)
|
||||||
|
supporters_path = os.path.join(root_dir, "data", "supporters.json")
|
||||||
|
|
||||||
|
if os.path.exists(supporters_path):
|
||||||
|
with open(supporters_path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
self._logger.debug(f"Failed to load supporters data: {e}")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"specialThanks": [],
|
||||||
|
"allSupporters": [],
|
||||||
|
"totalCount": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
async def get_supporters(self, request: web.Request) -> web.Response:
|
||||||
|
"""Return supporters data as JSON."""
|
||||||
|
try:
|
||||||
|
supporters = self._load_supporters()
|
||||||
|
return web.json_response({"success": True, "supporters": supporters})
|
||||||
|
except Exception as exc:
|
||||||
|
self._logger.error("Error loading supporters: %s", exc, exc_info=True)
|
||||||
|
return web.json_response(
|
||||||
|
{"success": False, "error": str(exc)}, status=500
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SettingsHandler:
|
class SettingsHandler:
|
||||||
"""Sync settings between backend and frontend."""
|
"""Sync settings between backend and frontend."""
|
||||||
|
|
||||||
@@ -1482,6 +1522,7 @@ class MiscHandlerSet:
|
|||||||
metadata_archive: MetadataArchiveHandler,
|
metadata_archive: MetadataArchiveHandler,
|
||||||
filesystem: FileSystemHandler,
|
filesystem: FileSystemHandler,
|
||||||
custom_words: CustomWordsHandler,
|
custom_words: CustomWordsHandler,
|
||||||
|
supporters: SupportersHandler,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.health = health
|
self.health = health
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
@@ -1494,6 +1535,7 @@ class MiscHandlerSet:
|
|||||||
self.metadata_archive = metadata_archive
|
self.metadata_archive = metadata_archive
|
||||||
self.filesystem = filesystem
|
self.filesystem = filesystem
|
||||||
self.custom_words = custom_words
|
self.custom_words = custom_words
|
||||||
|
self.supporters = supporters
|
||||||
|
|
||||||
def to_route_mapping(
|
def to_route_mapping(
|
||||||
self,
|
self,
|
||||||
@@ -1522,6 +1564,7 @@ class MiscHandlerSet:
|
|||||||
"open_file_location": self.filesystem.open_file_location,
|
"open_file_location": self.filesystem.open_file_location,
|
||||||
"open_settings_location": self.filesystem.open_settings_location,
|
"open_settings_location": self.filesystem.open_settings_location,
|
||||||
"search_custom_words": self.custom_words.search_custom_words,
|
"search_custom_words": self.custom_words.search_custom_words,
|
||||||
|
"get_supporters": self.supporters.get_supporters,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,27 @@ class ModelPageView:
|
|||||||
self._logger = logger
|
self._logger = logger
|
||||||
self._app_version = self._get_app_version()
|
self._app_version = self._get_app_version()
|
||||||
|
|
||||||
|
def _load_supporters(self) -> dict:
|
||||||
|
"""Load supporters data from JSON file."""
|
||||||
|
try:
|
||||||
|
current_file = os.path.abspath(__file__)
|
||||||
|
root_dir = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(current_file)))
|
||||||
|
)
|
||||||
|
supporters_path = os.path.join(root_dir, "data", "supporters.json")
|
||||||
|
|
||||||
|
if os.path.exists(supporters_path):
|
||||||
|
with open(supporters_path, "r", encoding="utf-8") as f:
|
||||||
|
return json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
self._logger.debug(f"Failed to load supporters data: {e}")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"specialThanks": [],
|
||||||
|
"allSupporters": [],
|
||||||
|
"totalCount": 0
|
||||||
|
}
|
||||||
|
|
||||||
def _get_app_version(self) -> str:
|
def _get_app_version(self) -> str:
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
short_hash = "stable"
|
short_hash = "stable"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ MISC_ROUTE_DEFINITIONS: tuple[RouteDefinition, ...] = (
|
|||||||
RouteDefinition("GET", "/api/lm/settings/libraries", "get_settings_libraries"),
|
RouteDefinition("GET", "/api/lm/settings/libraries", "get_settings_libraries"),
|
||||||
RouteDefinition("POST", "/api/lm/settings/libraries/activate", "activate_library"),
|
RouteDefinition("POST", "/api/lm/settings/libraries/activate", "activate_library"),
|
||||||
RouteDefinition("GET", "/api/lm/health-check", "health_check"),
|
RouteDefinition("GET", "/api/lm/health-check", "health_check"),
|
||||||
|
RouteDefinition("GET", "/api/lm/supporters", "get_supporters"),
|
||||||
RouteDefinition("POST", "/api/lm/open-file-location", "open_file_location"),
|
RouteDefinition("POST", "/api/lm/open-file-location", "open_file_location"),
|
||||||
RouteDefinition("POST", "/api/lm/update-usage-stats", "update_usage_stats"),
|
RouteDefinition("POST", "/api/lm/update-usage-stats", "update_usage_stats"),
|
||||||
RouteDefinition("GET", "/api/lm/get-usage-stats", "get_usage_stats"),
|
RouteDefinition("GET", "/api/lm/get-usage-stats", "get_usage_stats"),
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ from .handlers.misc_handlers import (
|
|||||||
NodeRegistry,
|
NodeRegistry,
|
||||||
NodeRegistryHandler,
|
NodeRegistryHandler,
|
||||||
SettingsHandler,
|
SettingsHandler,
|
||||||
|
SupportersHandler,
|
||||||
TrainedWordsHandler,
|
TrainedWordsHandler,
|
||||||
UsageStatsHandler,
|
UsageStatsHandler,
|
||||||
build_service_registry_adapter,
|
build_service_registry_adapter,
|
||||||
@@ -119,6 +120,7 @@ class MiscRoutes:
|
|||||||
metadata_provider_factory=self._metadata_provider_factory,
|
metadata_provider_factory=self._metadata_provider_factory,
|
||||||
)
|
)
|
||||||
custom_words = CustomWordsHandler()
|
custom_words = CustomWordsHandler()
|
||||||
|
supporters = SupportersHandler()
|
||||||
|
|
||||||
return self._handler_set_factory(
|
return self._handler_set_factory(
|
||||||
health=health,
|
health=health,
|
||||||
@@ -132,6 +134,7 @@ class MiscRoutes:
|
|||||||
metadata_archive=metadata_archive,
|
metadata_archive=metadata_archive,
|
||||||
filesystem=filesystem,
|
filesystem=filesystem,
|
||||||
custom_words=custom_words,
|
custom_words=custom_words,
|
||||||
|
supporters=supporters,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ body {
|
|||||||
--space-1: calc(8px * 1);
|
--space-1: calc(8px * 1);
|
||||||
--space-2: calc(8px * 2);
|
--space-2: calc(8px * 2);
|
||||||
--space-3: calc(8px * 3);
|
--space-3: calc(8px * 3);
|
||||||
|
--space-4: calc(8px * 4);
|
||||||
|
|
||||||
/* Z-index Scale */
|
/* Z-index Scale */
|
||||||
--z-base: 10;
|
--z-base: 10;
|
||||||
@@ -77,6 +78,7 @@ body {
|
|||||||
|
|
||||||
/* Border Radius */
|
/* Border Radius */
|
||||||
--border-radius-base: 12px;
|
--border-radius-base: 12px;
|
||||||
|
--border-radius-md: 12px;
|
||||||
--border-radius-sm: 8px;
|
--border-radius-sm: 8px;
|
||||||
--border-radius-xs: 4px;
|
--border-radius-xs: 4px;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,26 @@
|
|||||||
/* Support Modal Styles */
|
/* Support Modal Styles */
|
||||||
.support-modal {
|
.support-modal {
|
||||||
max-width: 570px;
|
max-width: 1000px;
|
||||||
|
width: 90vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Two-column layout */
|
||||||
|
.support-container {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-3);
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-left {
|
||||||
|
flex: 0 0 42%;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-right {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
border-left: 1px solid var(--lora-border);
|
||||||
|
padding-left: var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.support-header {
|
.support-header {
|
||||||
@@ -214,6 +234,11 @@
|
|||||||
.support-links {
|
.support-links {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.support-modal {
|
||||||
|
width: 95vw;
|
||||||
|
max-width: 95vw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Civitai link styles */
|
/* Civitai link styles */
|
||||||
@@ -240,3 +265,180 @@
|
|||||||
border-color: var(--lora-accent);
|
border-color: var(--lora-accent);
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Supporters Section Styles */
|
||||||
|
.supporters-section {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-header {
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-2);
|
||||||
|
margin: 0 0 var(--space-1) 0;
|
||||||
|
font-size: 1.3em !important;
|
||||||
|
color: var(--lora-accent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-title i {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-subtitle {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.95em;
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-group {
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-group-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 0 0 var(--space-2) 0;
|
||||||
|
font-size: 1em;
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.8;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-group-title i {
|
||||||
|
color: var(--lora-accent);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Special Thanks - Clean Card Style */
|
||||||
|
.special-thanks-group {
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.special-thanks-group .supporters-group-title {
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.special-thanks-group .supporters-group-title i {
|
||||||
|
color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-supporters-group .supporters-group-title i {
|
||||||
|
color: var(--lora-error);
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-special-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-special-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--space-2) var(--space-3);
|
||||||
|
background: var(--card-bg);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-left: 3px solid var(--lora-accent);
|
||||||
|
border-radius: var(--border-radius-sm);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-special-card:hover {
|
||||||
|
border-color: var(--lora-accent);
|
||||||
|
border-left-color: var(--lora-accent);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
transform: translateX(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-special-card .supporter-special-name {
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-color);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-special-card:hover .supporter-special-name {
|
||||||
|
color: var(--lora-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All Supporters - Elegant Text Flow */
|
||||||
|
.all-supporters-group {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-supporters-group .supporters-group-title {
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-all-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
line-height: 2.2;
|
||||||
|
max-height: 550px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: var(--space-2) 0;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-name-item {
|
||||||
|
font-size: 0.95em;
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.85;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-name-item:hover {
|
||||||
|
opacity: 1;
|
||||||
|
color: var(--lora-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporter-separator {
|
||||||
|
margin: 0 10px;
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.25;
|
||||||
|
font-weight: 300;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.support-container {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-left {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-right {
|
||||||
|
border-left: none;
|
||||||
|
border-top: 1px solid var(--lora-border);
|
||||||
|
padding-left: 0;
|
||||||
|
padding-top: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-all-list {
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.supporters-special-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import { FilterManager } from '../managers/FilterManager.js';
|
|||||||
import { initPageState } from '../state/index.js';
|
import { initPageState } from '../state/index.js';
|
||||||
import { getStorageItem } from '../utils/storageHelpers.js';
|
import { getStorageItem } from '../utils/storageHelpers.js';
|
||||||
import { updateElementAttribute } from '../utils/i18nHelpers.js';
|
import { updateElementAttribute } from '../utils/i18nHelpers.js';
|
||||||
|
import { renderSupporters } from '../services/supportersService.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Header.js - Manages the application header behavior across different pages
|
* Header.js - Manages the application header behavior across different pages
|
||||||
@@ -85,9 +86,15 @@ export class HeaderManager {
|
|||||||
// Handle support toggle
|
// Handle support toggle
|
||||||
const supportToggle = document.getElementById('supportToggleBtn');
|
const supportToggle = document.getElementById('supportToggleBtn');
|
||||||
if (supportToggle) {
|
if (supportToggle) {
|
||||||
supportToggle.addEventListener('click', () => {
|
supportToggle.addEventListener('click', async () => {
|
||||||
if (window.modalManager) {
|
if (window.modalManager) {
|
||||||
window.modalManager.toggleModal('supportModal');
|
window.modalManager.toggleModal('supportModal');
|
||||||
|
// Load supporters data when modal opens
|
||||||
|
try {
|
||||||
|
await renderSupporters();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading supporters:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
104
static/js/services/supportersService.js
Normal file
104
static/js/services/supportersService.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* Supporters service - Fetches and manages supporters data
|
||||||
|
*/
|
||||||
|
|
||||||
|
let supportersData = null;
|
||||||
|
let isLoading = false;
|
||||||
|
let loadPromise = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch supporters data from the API
|
||||||
|
* @returns {Promise<Object>} Supporters data
|
||||||
|
*/
|
||||||
|
export async function fetchSupporters() {
|
||||||
|
// Return cached data if available
|
||||||
|
if (supportersData) {
|
||||||
|
return supportersData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return existing promise if already loading
|
||||||
|
if (isLoading && loadPromise) {
|
||||||
|
return loadPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading = true;
|
||||||
|
loadPromise = fetch('/api/lm/supporters')
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch supporters: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
if (data.success && data.supporters) {
|
||||||
|
supportersData = data.supporters;
|
||||||
|
return supportersData;
|
||||||
|
}
|
||||||
|
throw new Error(data.error || 'Failed to load supporters data');
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading supporters:', error);
|
||||||
|
// Return empty data on error
|
||||||
|
return {
|
||||||
|
specialThanks: [],
|
||||||
|
allSupporters: [],
|
||||||
|
totalCount: 0
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
isLoading = false;
|
||||||
|
loadPromise = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
return loadPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear cached supporters data
|
||||||
|
*/
|
||||||
|
export function clearSupportersCache() {
|
||||||
|
supportersData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render supporters in the support modal
|
||||||
|
*/
|
||||||
|
export async function renderSupporters() {
|
||||||
|
const supporters = await fetchSupporters();
|
||||||
|
|
||||||
|
// Update subtitle with total count
|
||||||
|
const subtitleEl = document.getElementById('supportersSubtitle');
|
||||||
|
if (subtitleEl) {
|
||||||
|
// Get the translation key and replace count
|
||||||
|
const originalText = subtitleEl.textContent;
|
||||||
|
// Replace the count in the text (simple approach)
|
||||||
|
subtitleEl.textContent = originalText.replace(/\d+/, supporters.totalCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render special thanks
|
||||||
|
const specialThanksGrid = document.getElementById('specialThanksGrid');
|
||||||
|
if (specialThanksGrid && supporters.specialThanks) {
|
||||||
|
specialThanksGrid.innerHTML = supporters.specialThanks
|
||||||
|
.map(supporter => `
|
||||||
|
<div class="supporter-special-card" title="${supporter}">
|
||||||
|
<span class="supporter-special-name">${supporter}</span>
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render all supporters
|
||||||
|
const supportersGrid = document.getElementById('supportersGrid');
|
||||||
|
if (supportersGrid && supporters.allSupporters) {
|
||||||
|
supportersGrid.innerHTML = supporters.allSupporters
|
||||||
|
.map((supporter, index, array) => {
|
||||||
|
const separator = index < array.length - 1
|
||||||
|
? '<span class="supporter-separator">·</span>'
|
||||||
|
: '';
|
||||||
|
return `
|
||||||
|
<span class="supporter-name-item" title="${supporter}">${supporter}</span>${separator}
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,90 +2,133 @@
|
|||||||
<div id="supportModal" class="modal">
|
<div id="supportModal" class="modal">
|
||||||
<div class="modal-content support-modal">
|
<div class="modal-content support-modal">
|
||||||
<button class="close" onclick="modalManager.closeModal('supportModal')">×</button>
|
<button class="close" onclick="modalManager.closeModal('supportModal')">×</button>
|
||||||
<div class="support-header">
|
|
||||||
<i class="fas fa-heart support-icon"></i>
|
|
||||||
<h2>{{ t('support.title') }}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="support-content">
|
|
||||||
<p>{{ t('support.message') }}</p>
|
|
||||||
|
|
||||||
<div class="support-section">
|
<div class="support-container">
|
||||||
<h3><i class="fas fa-comment"></i> {{ t('support.feedback.title') }}</h3>
|
<!-- Left Side: Support Options -->
|
||||||
<p>{{ t('support.feedback.description') }}</p>
|
<div class="support-left">
|
||||||
<div class="support-links">
|
<div class="support-header">
|
||||||
<a href="https://github.com/willmiao/ComfyUI-Lora-Manager/issues/new" class="social-link" target="_blank">
|
<i class="fas fa-heart support-icon"></i>
|
||||||
<i class="fab fa-github"></i>
|
<h2>{{ t('support.title') }}</h2>
|
||||||
<span>{{ t('support.links.submitGithubIssue') }}</span>
|
</div>
|
||||||
</a>
|
<div class="support-content">
|
||||||
<a href="https://discord.gg/vcqNrWVFvM" class="social-link" target="_blank">
|
<p>{{ t('support.message') }}</p>
|
||||||
<i class="fab fa-discord"></i>
|
|
||||||
<span>{{ t('support.links.joinDiscord') }}</span>
|
<div class="support-section">
|
||||||
</a>
|
<h3><i class="fas fa-comment"></i> {{ t('support.feedback.title') }}</h3>
|
||||||
|
<p>{{ t('support.feedback.description') }}</p>
|
||||||
|
<div class="support-links">
|
||||||
|
<a href="https://github.com/willmiao/ComfyUI-Lora-Manager/issues/new" class="social-link" target="_blank">
|
||||||
|
<i class="fab fa-github"></i>
|
||||||
|
<span>{{ t('support.links.submitGithubIssue') }}</span>
|
||||||
|
</a>
|
||||||
|
<a href="https://discord.gg/vcqNrWVFvM" class="social-link" target="_blank">
|
||||||
|
<i class="fab fa-discord"></i>
|
||||||
|
<span>{{ t('support.links.joinDiscord') }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="support-section">
|
||||||
|
<h3><i class="fas fa-rss"></i> {{ t('support.sections.followUpdates') }}</h3>
|
||||||
|
<div class="support-links">
|
||||||
|
<a href="https://www.youtube.com/@pixelpaws-ai" class="social-link" target="_blank">
|
||||||
|
<i class="fab fa-youtube"></i>
|
||||||
|
<span>{{ t('support.links.youtubeChannel') }}</span>
|
||||||
|
</a>
|
||||||
|
<a href="https://civitai.com/user/PixelPawsAI" class="social-link civitai-link" target="_blank">
|
||||||
|
<svg class="civitai-icon" viewBox="0 0 225 225" width="20" height="20">
|
||||||
|
<g transform="translate(0,225) scale(0.1,-0.1)" fill="currentColor">
|
||||||
|
<path d="M950 1899 c-96 -55 -262 -150 -367 -210 -106 -61 -200 -117 -208
|
||||||
|
-125 -13 -13 -15 -76 -15 -443 0 -395 1 -429 18 -443 9 -9 116 -73 237 -143
|
||||||
|
121 -70 283 -163 359 -208 76 -45 146 -80 155 -80 9 1 183 98 386 215 l370
|
||||||
|
215 2 444 3 444 -376 215 c-206 118 -378 216 -382 217 -4 1 -86 -43 -182 -98z
|
||||||
|
m346 -481 l163 -93 1 -57 0 -58 -89 0 c-87 0 -91 1 -166 44 l-78 45 -51 -30
|
||||||
|
c-28 -17 -61 -35 -73 -41 -21 -10 -23 -18 -23 -99 l0 -87 71 -41 c39 -23 73
|
||||||
|
-41 76 -41 3 0 37 18 75 40 68 39 72 40 164 40 l94 0 0 -53 c0 -60 23 -41
|
||||||
|
-198 -168 l-133 -77 -92 52 c-51 29 -126 73 -167 97 l-75 45 0 193 0 192 164
|
||||||
|
95 c91 52 167 94 169 94 2 0 78 -42 168 -92z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span>{{ t('support.links.civitaiProfile') }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="support-section">
|
||||||
|
<h3><i class="fas fa-coffee"></i> {{ t('support.sections.buyMeCoffee') }}</h3>
|
||||||
|
<p>{{ t('support.sections.coffeeDescription') }}</p>
|
||||||
|
<a href="https://ko-fi.com/pixelpawsai" class="kofi-button" target="_blank">
|
||||||
|
<i class="fas fa-mug-hot"></i>
|
||||||
|
<span>{{ t('support.links.supportKofi') }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Patreon Support Section -->
|
||||||
|
<div class="support-section">
|
||||||
|
<h3><i class="fab fa-patreon"></i> {{ t('support.sections.becomePatron') }}</h3>
|
||||||
|
<p>{{ t('support.sections.patronDescription') }}</p>
|
||||||
|
<a href="https://patreon.com/PixelPawsAI" class="patreon-button" target="_blank">
|
||||||
|
<i class="fab fa-patreon"></i>
|
||||||
|
<span>{{ t('support.links.supportPatreon') }}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- New section for Chinese payment methods -->
|
||||||
|
<div class="support-section">
|
||||||
|
<h3><i class="fas fa-qrcode"></i> {{ t('support.sections.wechatSupport') }}</h3>
|
||||||
|
<p>{{ t('support.sections.wechatDescription') }}</p>
|
||||||
|
<button class="secondary-btn qrcode-toggle" id="toggleQRCode">
|
||||||
|
<i class="fas fa-qrcode"></i>
|
||||||
|
<span class="toggle-text">{{ t('support.sections.showWechatQR') }}</span>
|
||||||
|
<i class="fas fa-chevron-down toggle-icon"></i>
|
||||||
|
</button>
|
||||||
|
<div class="qrcode-container" id="qrCodeContainer">
|
||||||
|
<img src="/loras_static/images/wechat-qr.webp" alt="WeChat Pay QR Code" class="qrcode-image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="support-footer">
|
||||||
|
<p>{{ t('support.footer') }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="support-section">
|
<!-- Right Side: Supporters -->
|
||||||
<h3><i class="fas fa-rss"></i> {{ t('support.sections.followUpdates') }}</h3>
|
<div class="support-right">
|
||||||
<div class="support-links">
|
<div class="supporters-section">
|
||||||
<a href="https://www.youtube.com/@pixelpaws-ai" class="social-link" target="_blank">
|
<div class="supporters-header">
|
||||||
<i class="fab fa-youtube"></i>
|
<h2 class="supporters-title">
|
||||||
<span>{{ t('support.links.youtubeChannel') }}</span>
|
<i class="fas fa-hands-helping"></i>
|
||||||
</a>
|
{{ t('support.supporters.title') }}
|
||||||
<a href="https://civitai.com/user/PixelPawsAI" class="social-link civitai-link" target="_blank">
|
</h2>
|
||||||
<svg class="civitai-icon" viewBox="0 0 225 225" width="20" height="20">
|
<p class="supporters-subtitle" id="supportersSubtitle">
|
||||||
<g transform="translate(0,225) scale(0.1,-0.1)" fill="currentColor">
|
{{ t('support.supporters.subtitle', count=0) }}
|
||||||
<path d="M950 1899 c-96 -55 -262 -150 -367 -210 -106 -61 -200 -117 -208
|
</p>
|
||||||
-125 -13 -13 -15 -76 -15 -443 0 -395 1 -429 18 -443 9 -9 116 -73 237 -143
|
</div>
|
||||||
121 -70 283 -163 359 -208 76 -45 146 -80 155 -80 9 1 183 98 386 215 l370
|
|
||||||
215 2 444 3 444 -376 215 c-206 118 -378 216 -382 217 -4 1 -86 -43 -182 -98z
|
<!-- Special Thanks Section -->
|
||||||
m346 -481 l163 -93 1 -57 0 -58 -89 0 c-87 0 -91 1 -166 44 l-78 45 -51 -30
|
<div class="supporters-group special-thanks-group">
|
||||||
c-28 -17 -61 -35 -73 -41 -21 -10 -23 -18 -23 -99 l0 -87 71 -41 c39 -23 73
|
<h3 class="supporters-group-title">
|
||||||
-41 76 -41 3 0 37 18 75 40 68 39 72 40 164 40 l94 0 0 -53 c0 -60 23 -41
|
<i class="fas fa-star"></i>
|
||||||
-198 -168 l-133 -77 -92 52 c-51 29 -126 73 -167 97 l-75 45 0 193 0 192 164
|
{{ t('support.supporters.specialThanks') }}
|
||||||
95 c91 52 167 94 169 94 2 0 78 -42 168 -92z"/>
|
</h3>
|
||||||
</g>
|
<div class="supporters-special-grid" id="specialThanksGrid">
|
||||||
</svg>
|
<!-- Supporters will be loaded dynamically -->
|
||||||
<span>{{ t('support.links.civitaiProfile') }}</span>
|
</div>
|
||||||
</a>
|
</div>
|
||||||
|
|
||||||
|
<!-- All Supporters Section -->
|
||||||
|
<div class="supporters-group all-supporters-group">
|
||||||
|
<h3 class="supporters-group-title">
|
||||||
|
<i class="fas fa-heart"></i>
|
||||||
|
{{ t('support.supporters.allSupporters') }}
|
||||||
|
</h3>
|
||||||
|
<div class="supporters-all-list" id="supportersGrid">
|
||||||
|
<!-- Supporters will be loaded dynamically -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="support-section">
|
|
||||||
<h3><i class="fas fa-coffee"></i> {{ t('support.sections.buyMeCoffee') }}</h3>
|
|
||||||
<p>{{ t('support.sections.coffeeDescription') }}</p>
|
|
||||||
<a href="https://ko-fi.com/pixelpawsai" class="kofi-button" target="_blank">
|
|
||||||
<i class="fas fa-mug-hot"></i>
|
|
||||||
<span>{{ t('support.links.supportKofi') }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Patreon Support Section -->
|
|
||||||
<div class="support-section">
|
|
||||||
<h3><i class="fab fa-patreon"></i> {{ t('support.sections.becomePatron') }}</h3>
|
|
||||||
<p>{{ t('support.sections.patronDescription') }}</p>
|
|
||||||
<a href="https://patreon.com/PixelPawsAI" class="patreon-button" target="_blank">
|
|
||||||
<i class="fab fa-patreon"></i>
|
|
||||||
<span>{{ t('support.links.supportPatreon') }}</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- New section for Chinese payment methods -->
|
|
||||||
<div class="support-section">
|
|
||||||
<h3><i class="fas fa-qrcode"></i> {{ t('support.sections.wechatSupport') }}</h3>
|
|
||||||
<p>{{ t('support.sections.wechatDescription') }}</p>
|
|
||||||
<button class="secondary-btn qrcode-toggle" id="toggleQRCode">
|
|
||||||
<i class="fas fa-qrcode"></i>
|
|
||||||
<span class="toggle-text">{{ t('support.sections.showWechatQR') }}</span>
|
|
||||||
<i class="fas fa-chevron-down toggle-icon"></i>
|
|
||||||
</button>
|
|
||||||
<div class="qrcode-container" id="qrCodeContainer">
|
|
||||||
<img src="/loras_static/images/wechat-qr.webp" alt="WeChat Pay QR Code" class="qrcode-image">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="support-footer">
|
|
||||||
<p>{{ t('support.footer') }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
Reference in New Issue
Block a user