Initial working version
This commit is contained in:
commit
0b27ef2b30
|
@ -0,0 +1,14 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
fastapi = "*"
|
||||
uvicorn = "*"
|
||||
jinja2 = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.12"
|
|
@ -0,0 +1,300 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "12e13c349bc30c36612e452e3ee8b8f2f05b156bb788515a14a94f70aed33cf2"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.12"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"annotated-types": {
|
||||
"hashes": [
|
||||
"sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53",
|
||||
"sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"anyio": {
|
||||
"hashes": [
|
||||
"sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028",
|
||||
"sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==4.9.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202",
|
||||
"sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"
|
||||
],
|
||||
"markers": "python_version >= '3.10'",
|
||||
"version": "==8.2.1"
|
||||
},
|
||||
"fastapi": {
|
||||
"hashes": [
|
||||
"sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681",
|
||||
"sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.115.12"
|
||||
},
|
||||
"h11": {
|
||||
"hashes": [
|
||||
"sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1",
|
||||
"sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.16.0"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
|
||||
"sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==3.10"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d",
|
||||
"sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.1.6"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4",
|
||||
"sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30",
|
||||
"sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0",
|
||||
"sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9",
|
||||
"sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396",
|
||||
"sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13",
|
||||
"sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028",
|
||||
"sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca",
|
||||
"sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557",
|
||||
"sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832",
|
||||
"sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0",
|
||||
"sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b",
|
||||
"sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579",
|
||||
"sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a",
|
||||
"sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c",
|
||||
"sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff",
|
||||
"sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c",
|
||||
"sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22",
|
||||
"sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094",
|
||||
"sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb",
|
||||
"sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e",
|
||||
"sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5",
|
||||
"sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a",
|
||||
"sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d",
|
||||
"sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a",
|
||||
"sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b",
|
||||
"sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8",
|
||||
"sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225",
|
||||
"sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c",
|
||||
"sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144",
|
||||
"sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f",
|
||||
"sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87",
|
||||
"sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d",
|
||||
"sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93",
|
||||
"sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf",
|
||||
"sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158",
|
||||
"sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84",
|
||||
"sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb",
|
||||
"sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48",
|
||||
"sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171",
|
||||
"sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c",
|
||||
"sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6",
|
||||
"sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd",
|
||||
"sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d",
|
||||
"sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1",
|
||||
"sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d",
|
||||
"sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca",
|
||||
"sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a",
|
||||
"sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29",
|
||||
"sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe",
|
||||
"sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798",
|
||||
"sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c",
|
||||
"sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8",
|
||||
"sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f",
|
||||
"sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f",
|
||||
"sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a",
|
||||
"sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178",
|
||||
"sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0",
|
||||
"sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79",
|
||||
"sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430",
|
||||
"sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==3.0.2"
|
||||
},
|
||||
"pydantic": {
|
||||
"hashes": [
|
||||
"sha256:7f853db3d0ce78ce8bbb148c401c2cdd6431b3473c0cdff2755c7690952a7b7a",
|
||||
"sha256:f9c26ba06f9747749ca1e5c94d6a85cb84254577553c8785576fd38fa64dc0f7"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==2.11.5"
|
||||
},
|
||||
"pydantic-core": {
|
||||
"hashes": [
|
||||
"sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d",
|
||||
"sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac",
|
||||
"sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02",
|
||||
"sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56",
|
||||
"sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4",
|
||||
"sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22",
|
||||
"sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef",
|
||||
"sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec",
|
||||
"sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d",
|
||||
"sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b",
|
||||
"sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a",
|
||||
"sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f",
|
||||
"sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052",
|
||||
"sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab",
|
||||
"sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916",
|
||||
"sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c",
|
||||
"sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf",
|
||||
"sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27",
|
||||
"sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a",
|
||||
"sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8",
|
||||
"sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7",
|
||||
"sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612",
|
||||
"sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1",
|
||||
"sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039",
|
||||
"sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca",
|
||||
"sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7",
|
||||
"sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a",
|
||||
"sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6",
|
||||
"sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782",
|
||||
"sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b",
|
||||
"sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7",
|
||||
"sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025",
|
||||
"sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849",
|
||||
"sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7",
|
||||
"sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b",
|
||||
"sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa",
|
||||
"sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e",
|
||||
"sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea",
|
||||
"sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac",
|
||||
"sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51",
|
||||
"sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e",
|
||||
"sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162",
|
||||
"sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65",
|
||||
"sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2",
|
||||
"sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954",
|
||||
"sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b",
|
||||
"sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de",
|
||||
"sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc",
|
||||
"sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64",
|
||||
"sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb",
|
||||
"sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9",
|
||||
"sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101",
|
||||
"sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d",
|
||||
"sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef",
|
||||
"sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3",
|
||||
"sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1",
|
||||
"sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5",
|
||||
"sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88",
|
||||
"sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d",
|
||||
"sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290",
|
||||
"sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e",
|
||||
"sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d",
|
||||
"sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808",
|
||||
"sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc",
|
||||
"sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d",
|
||||
"sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc",
|
||||
"sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e",
|
||||
"sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640",
|
||||
"sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30",
|
||||
"sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e",
|
||||
"sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9",
|
||||
"sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a",
|
||||
"sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9",
|
||||
"sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f",
|
||||
"sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb",
|
||||
"sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5",
|
||||
"sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab",
|
||||
"sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d",
|
||||
"sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572",
|
||||
"sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593",
|
||||
"sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29",
|
||||
"sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535",
|
||||
"sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1",
|
||||
"sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f",
|
||||
"sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8",
|
||||
"sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf",
|
||||
"sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246",
|
||||
"sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9",
|
||||
"sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011",
|
||||
"sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9",
|
||||
"sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a",
|
||||
"sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3",
|
||||
"sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6",
|
||||
"sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8",
|
||||
"sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a",
|
||||
"sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2",
|
||||
"sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c",
|
||||
"sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6",
|
||||
"sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==2.33.2"
|
||||
},
|
||||
"sniffio": {
|
||||
"hashes": [
|
||||
"sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2",
|
||||
"sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.3.1"
|
||||
},
|
||||
"starlette": {
|
||||
"hashes": [
|
||||
"sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35",
|
||||
"sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==0.46.2"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c",
|
||||
"sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==4.13.2"
|
||||
},
|
||||
"typing-inspection": {
|
||||
"hashes": [
|
||||
"sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51",
|
||||
"sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"
|
||||
],
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"uvicorn": {
|
||||
"hashes": [
|
||||
"sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328",
|
||||
"sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": "python_version >= '3.9'",
|
||||
"version": "==0.34.2"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
from pydantic import BaseModel
|
||||
|
||||
class ColorUpdate(BaseModel):
|
||||
barId: str
|
||||
color: str
|
||||
|
||||
class PositionUpdate(BaseModel):
|
||||
barId: str
|
||||
x: int
|
||||
y: int
|
||||
|
||||
class CreateBar(BaseModel):
|
||||
barId: str
|
||||
url: str
|
||||
color: str
|
||||
x: int
|
||||
y: int
|
||||
|
||||
class DeleteBar(BaseModel):
|
||||
barId: str
|
|
@ -0,0 +1,57 @@
|
|||
from fastapi import APIRouter, HTTPException
|
||||
from .models import ColorUpdate, PositionUpdate, CreateBar, DeleteBar
|
||||
from .settings_manager import SettingsManager
|
||||
|
||||
router = APIRouter(prefix="/api")
|
||||
settings_manager = SettingsManager()
|
||||
|
||||
@router.get("/settings")
|
||||
async def get_settings():
|
||||
try:
|
||||
return settings_manager.load_settings()
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Error reading settings: {str(e)}")
|
||||
|
||||
@router.post("/settings/color")
|
||||
async def update_color(color_update: ColorUpdate):
|
||||
try:
|
||||
settings_manager.update_color(color_update.barId, color_update.color)
|
||||
return {"success": True, "message": f"Color updated for {color_update.barId}"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Error updating settings: {str(e)}")
|
||||
|
||||
@router.post("/settings/position")
|
||||
async def update_position(position_update: PositionUpdate):
|
||||
try:
|
||||
settings_manager.update_position(position_update.barId, position_update.x, position_update.y)
|
||||
return {"success": True, "message": f"Position updated for {position_update.barId}"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Error updating settings: {str(e)}")
|
||||
|
||||
@router.post("/settings/create")
|
||||
async def create_bar(create_bar: CreateBar):
|
||||
try:
|
||||
if settings_manager.bar_exists(create_bar.barId):
|
||||
raise HTTPException(status_code=400, detail=f"Bar {create_bar.barId} already exists")
|
||||
|
||||
settings_manager.create_bar(
|
||||
create_bar.barId,
|
||||
create_bar.url,
|
||||
create_bar.color,
|
||||
create_bar.x,
|
||||
create_bar.y
|
||||
)
|
||||
return {"success": True, "message": f"Bar {create_bar.barId} created"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Error creating bar: {str(e)}")
|
||||
|
||||
@router.delete("/settings/delete")
|
||||
async def delete_bar(delete_bar: DeleteBar):
|
||||
try:
|
||||
if not settings_manager.bar_exists(delete_bar.barId):
|
||||
raise HTTPException(status_code=404, detail=f"Bar {delete_bar.barId} not found")
|
||||
|
||||
settings_manager.delete_bar(delete_bar.barId)
|
||||
return {"success": True, "message": f"Bar {delete_bar.barId} deleted"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Error deleting bar: {str(e)}")
|
|
@ -0,0 +1,51 @@
|
|||
import json
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
|
||||
class SettingsManager:
|
||||
def __init__(self, settings_file: str = "settings.json"):
|
||||
self.settings_file = settings_file
|
||||
|
||||
def load_settings(self) -> Dict[str, Any]:
|
||||
try:
|
||||
with open(self.settings_file, "r") as f:
|
||||
return json.load(f)
|
||||
except FileNotFoundError:
|
||||
return {}
|
||||
|
||||
def save_settings(self, settings: Dict[str, Any]) -> None:
|
||||
with open(self.settings_file, "w") as f:
|
||||
json.dump(settings, f, indent=2)
|
||||
|
||||
def update_color(self, bar_id: str, color: str) -> None:
|
||||
settings = self.load_settings()
|
||||
if bar_id in settings:
|
||||
settings[bar_id]["color"] = color
|
||||
self.save_settings(settings)
|
||||
|
||||
def update_position(self, bar_id: str, x: int, y: int) -> None:
|
||||
settings = self.load_settings()
|
||||
if bar_id in settings:
|
||||
settings[bar_id]["x"] = x
|
||||
settings[bar_id]["y"] = y
|
||||
self.save_settings(settings)
|
||||
|
||||
def create_bar(self, bar_id: str, url: str, color: str, x: int, y: int) -> None:
|
||||
settings = self.load_settings()
|
||||
settings[bar_id] = {
|
||||
"url": url,
|
||||
"color": color,
|
||||
"x": x,
|
||||
"y": y
|
||||
}
|
||||
self.save_settings(settings)
|
||||
|
||||
def delete_bar(self, bar_id: str) -> None:
|
||||
settings = self.load_settings()
|
||||
if bar_id in settings:
|
||||
del settings[bar_id]
|
||||
self.save_settings(settings)
|
||||
|
||||
def bar_exists(self, bar_id: str) -> bool:
|
||||
settings = self.load_settings()
|
||||
return bar_id in settings
|
|
@ -0,0 +1,20 @@
|
|||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from api.routes import router
|
||||
import uvicorn
|
||||
|
||||
app = FastAPI(title="Bar Control System", version="1.0.0")
|
||||
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
app.include_router(router)
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def read_root(request: Request):
|
||||
return templates.TemplateResponse("index.html", {"request": request})
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(app, host="0.0.0.0", port=8000, reload=True)
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"dj": {
|
||||
"url": "ws://192.168.4.1/ws",
|
||||
"color": "#1d011e",
|
||||
"x": 614,
|
||||
"y": 123
|
||||
},
|
||||
"bar2": {
|
||||
"url": "ws://192.168.4.1/ws",
|
||||
"color": "#3d0f00",
|
||||
"x": 616,
|
||||
"y": 330
|
||||
},
|
||||
"bar5": {
|
||||
"url": "ws://192.168.4.1/ws",
|
||||
"color": "#300d2a",
|
||||
"x": 618,
|
||||
"y": 567
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
export class ApiService {
|
||||
static async loadSettings() {
|
||||
try {
|
||||
const response = await fetch("/api/settings");
|
||||
const settings = await response.json();
|
||||
console.log("Settings loaded:", settings);
|
||||
return settings;
|
||||
} catch (error) {
|
||||
console.error("Failed to load settings:", error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static async createBar(barData) {
|
||||
const response = await fetch("/api/settings/create", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(barData),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async deleteBar(barId) {
|
||||
const response = await fetch("/api/settings/delete", {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ barId }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json();
|
||||
throw new Error(error.detail);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
static async saveColor(barId, color) {
|
||||
try {
|
||||
const response = await fetch("/api/settings/color", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ barId, color }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`Color saved for ${barId}: ${color}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to save color:", error);
|
||||
}
|
||||
}
|
||||
|
||||
static async savePosition(barId, x, y) {
|
||||
try {
|
||||
const response = await fetch("/api/settings/position", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ barId, x, y }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(`Position saved for ${barId}: ${x}, ${y}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to save position:", error);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
import { ApiService } from "./ApiService.js";
|
||||
import { DialogManager } from "./DialogManager.js";
|
||||
import { throttle, createStyledElement } from "./utils.js";
|
||||
|
||||
export class BarControlSystem {
|
||||
constructor() {
|
||||
this.settings = {};
|
||||
this.websockets = {};
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
await this.loadSettings();
|
||||
this.createControlPanel();
|
||||
this.renderColorPickers();
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = await ApiService.loadSettings();
|
||||
}
|
||||
|
||||
createControlPanel() {
|
||||
const panel = createStyledElement("div", {
|
||||
position: "fixed",
|
||||
top: "10px",
|
||||
right: "10px",
|
||||
padding: "15px",
|
||||
border: "2px solid #333",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "#f0f0f0",
|
||||
zIndex: "1000",
|
||||
});
|
||||
panel.id = "control-panel";
|
||||
|
||||
const title = createStyledElement(
|
||||
"h3",
|
||||
{
|
||||
margin: "0 0 10px 0",
|
||||
fontFamily: "Arial, sans-serif",
|
||||
},
|
||||
{ textContent: "Control Panel" },
|
||||
);
|
||||
|
||||
const buttonStyles = {
|
||||
padding: "8px 12px",
|
||||
border: "none",
|
||||
borderRadius: "4px",
|
||||
cursor: "pointer",
|
||||
color: "white",
|
||||
};
|
||||
|
||||
const createButton = createStyledElement(
|
||||
"button",
|
||||
{
|
||||
...buttonStyles,
|
||||
marginRight: "10px",
|
||||
backgroundColor: "#4CAF50",
|
||||
},
|
||||
{ textContent: "Create New Bar" },
|
||||
);
|
||||
|
||||
const refreshButton = createStyledElement(
|
||||
"button",
|
||||
{
|
||||
...buttonStyles,
|
||||
backgroundColor: "#2196F3",
|
||||
},
|
||||
{ textContent: "Refresh" },
|
||||
);
|
||||
|
||||
createButton.onclick = () => this.showCreateDialog();
|
||||
refreshButton.onclick = () => this.refresh();
|
||||
|
||||
panel.append(title, createButton, refreshButton);
|
||||
document.body.appendChild(panel);
|
||||
}
|
||||
|
||||
showCreateDialog() {
|
||||
DialogManager.showCreateDialog((barData) => this.createBar(barData));
|
||||
}
|
||||
|
||||
async createBar(barData) {
|
||||
if (!barData.barId) {
|
||||
alert("Bar ID is required");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await ApiService.createBar(barData);
|
||||
console.log(`Bar created: ${barData.barId}`);
|
||||
await this.refresh();
|
||||
} catch (error) {
|
||||
console.error("Failed to create bar:", error);
|
||||
alert(error.message || "Failed to create bar");
|
||||
}
|
||||
}
|
||||
|
||||
async deleteBar(barId) {
|
||||
if (!confirm(`Are you sure you want to delete bar ${barId}?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await ApiService.deleteBar(barId);
|
||||
console.log(`Bar deleted: ${barId}`);
|
||||
await this.refresh();
|
||||
} catch (error) {
|
||||
console.error("Failed to delete bar:", error);
|
||||
alert(error.message || "Failed to delete bar");
|
||||
}
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
// Close existing websockets
|
||||
Object.values(this.websockets).forEach((ws) => {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Remove existing color pickers
|
||||
Object.keys(this.settings).forEach((barId) => {
|
||||
const form = document.getElementById("color_form_" + barId);
|
||||
if (form) {
|
||||
form.remove();
|
||||
}
|
||||
});
|
||||
|
||||
this.websockets = {};
|
||||
await this.loadSettings();
|
||||
this.renderColorPickers();
|
||||
}
|
||||
|
||||
renderColorPickers() {
|
||||
Object.keys(this.settings).forEach((barId) => {
|
||||
const config = this.settings[barId];
|
||||
this.createColorPicker(barId, config);
|
||||
});
|
||||
}
|
||||
|
||||
makeDraggable(element, barId) {
|
||||
let isDragging = false;
|
||||
let startX, startY, initialX, initialY;
|
||||
|
||||
element.addEventListener("mousedown", (e) => {
|
||||
if (e.target.tagName === "BUTTON") return;
|
||||
|
||||
isDragging = true;
|
||||
startX = e.clientX;
|
||||
startY = e.clientY;
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
initialX = rect.left;
|
||||
initialY = rect.top;
|
||||
|
||||
element.style.cursor = "move";
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
if (!isDragging) return;
|
||||
|
||||
const deltaX = e.clientX - startX;
|
||||
const deltaY = e.clientY - startY;
|
||||
|
||||
const newX = initialX + deltaX;
|
||||
const newY = initialY + deltaY;
|
||||
|
||||
element.style.left = newX + "px";
|
||||
element.style.top = newY + "px";
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", () => {
|
||||
if (isDragging) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
ApiService.savePosition(barId, rect.left, rect.top);
|
||||
element.style.cursor = "default";
|
||||
}
|
||||
isDragging = false;
|
||||
});
|
||||
}
|
||||
|
||||
createColorPicker(barId, config) {
|
||||
const ws = new WebSocket(config["url"]);
|
||||
this.websockets[barId] = ws;
|
||||
|
||||
const form = createStyledElement("form", {
|
||||
position: "absolute",
|
||||
left: config["x"] + "px",
|
||||
top: config["y"] + "px",
|
||||
padding: "10px",
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "white",
|
||||
});
|
||||
form.id = "color_form_" + barId;
|
||||
|
||||
const label = createStyledElement(
|
||||
"label",
|
||||
{
|
||||
display: "block",
|
||||
marginBottom: "5px",
|
||||
fontFamily: "Arial, sans-serif",
|
||||
fontSize: "14px",
|
||||
},
|
||||
{
|
||||
htmlFor: "color_input_" + barId,
|
||||
textContent: barId,
|
||||
},
|
||||
);
|
||||
|
||||
const colorInput = createStyledElement(
|
||||
"input",
|
||||
{},
|
||||
{
|
||||
type: "color",
|
||||
id: "color_input_" + barId,
|
||||
name: barId,
|
||||
value: config["color"],
|
||||
},
|
||||
);
|
||||
|
||||
const deleteButton = createStyledElement(
|
||||
"button",
|
||||
{
|
||||
position: "absolute",
|
||||
top: "2px",
|
||||
right: "2px",
|
||||
width: "20px",
|
||||
height: "20px",
|
||||
backgroundColor: "#f44336",
|
||||
color: "white",
|
||||
border: "none",
|
||||
borderRadius: "50%",
|
||||
cursor: "pointer",
|
||||
fontSize: "12px",
|
||||
lineHeight: "1",
|
||||
},
|
||||
{
|
||||
type: "button",
|
||||
textContent: "×",
|
||||
},
|
||||
);
|
||||
|
||||
deleteButton.onclick = () => this.deleteBar(barId);
|
||||
|
||||
const throttledColorHandler = throttle((event) => {
|
||||
const color = event.target.value;
|
||||
console.log(`Color selected for ${barId}: ${color}`);
|
||||
|
||||
ApiService.saveColor(barId, color);
|
||||
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
const message = { color1: color };
|
||||
ws.send(JSON.stringify(message));
|
||||
} else {
|
||||
console.warn(
|
||||
`WebSocket not ready for ${barId}. ReadyState: ${ws.readyState}`,
|
||||
);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
colorInput.addEventListener("input", throttledColorHandler);
|
||||
|
||||
form.append(label, colorInput, deleteButton);
|
||||
document.body.appendChild(form);
|
||||
|
||||
this.makeDraggable(form, barId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
import { createStyledElement } from "./utils.js";
|
||||
|
||||
export class DialogManager {
|
||||
static showCreateDialog(onCreateCallback) {
|
||||
const dialog = createStyledElement("div", {
|
||||
position: "fixed",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
padding: "20px",
|
||||
border: "2px solid #333",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "white",
|
||||
zIndex: "1001",
|
||||
boxShadow: "0 4px 8px rgba(0,0,0,0.3)",
|
||||
});
|
||||
|
||||
const title = createStyledElement(
|
||||
"h3",
|
||||
{ margin: "0 0 15px 0" },
|
||||
{ textContent: "Create New Bar" },
|
||||
);
|
||||
|
||||
const inputStyles = {
|
||||
display: "block",
|
||||
margin: "5px 0",
|
||||
padding: "8px",
|
||||
width: "200px",
|
||||
};
|
||||
|
||||
const barIdInput = createStyledElement("input", inputStyles, {
|
||||
type: "text",
|
||||
placeholder: "Bar ID",
|
||||
});
|
||||
|
||||
const urlInput = createStyledElement("input", inputStyles, {
|
||||
type: "text",
|
||||
placeholder: "WebSocket URL",
|
||||
value: "192.168.4.1",
|
||||
});
|
||||
|
||||
const colorInput = createStyledElement("input", inputStyles, {
|
||||
type: "color",
|
||||
value: "#ff0000",
|
||||
});
|
||||
|
||||
const xInput = createStyledElement("input", inputStyles, {
|
||||
type: "number",
|
||||
placeholder: "X Position",
|
||||
value: "100",
|
||||
});
|
||||
|
||||
const yInput = createStyledElement("input", inputStyles, {
|
||||
type: "number",
|
||||
placeholder: "Y Position",
|
||||
value: "100",
|
||||
});
|
||||
|
||||
const buttonStyles = {
|
||||
padding: "8px 12px",
|
||||
border: "none",
|
||||
borderRadius: "4px",
|
||||
cursor: "pointer",
|
||||
color: "white",
|
||||
};
|
||||
|
||||
const createBtn = createStyledElement(
|
||||
"button",
|
||||
{
|
||||
...buttonStyles,
|
||||
margin: "10px 5px 0 0",
|
||||
backgroundColor: "#4CAF50",
|
||||
},
|
||||
{ textContent: "Create" },
|
||||
);
|
||||
|
||||
const cancelBtn = createStyledElement(
|
||||
"button",
|
||||
{
|
||||
...buttonStyles,
|
||||
margin: "10px 0 0 0",
|
||||
backgroundColor: "#f44336",
|
||||
},
|
||||
{ textContent: "Cancel" },
|
||||
);
|
||||
|
||||
createBtn.onclick = () => {
|
||||
const barData = {
|
||||
barId: barIdInput.value,
|
||||
url: `ws://${urlInput.value}/ws`,
|
||||
color: colorInput.value,
|
||||
x: parseInt(xInput.value),
|
||||
y: parseInt(yInput.value),
|
||||
};
|
||||
onCreateCallback(barData);
|
||||
document.body.removeChild(dialog);
|
||||
};
|
||||
|
||||
cancelBtn.onclick = () => document.body.removeChild(dialog);
|
||||
|
||||
dialog.append(
|
||||
title,
|
||||
barIdInput,
|
||||
urlInput,
|
||||
colorInput,
|
||||
xInput,
|
||||
yInput,
|
||||
createBtn,
|
||||
cancelBtn,
|
||||
);
|
||||
document.body.appendChild(dialog);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
padding: 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
section {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.color-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 6px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.color-picker-item {
|
||||
position: absolute;
|
||||
background: white;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.color-picker-item h4 {
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.color-picker-item input[type="color"] {
|
||||
width: 60px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { BarControlSystem } from "./BarControlSystem.js";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
new BarControlSystem();
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
export function throttle(func, delay) {
|
||||
let timeoutId;
|
||||
let lastExecTime = 0;
|
||||
return function (...args) {
|
||||
const currentTime = Date.now();
|
||||
|
||||
if (currentTime - lastExecTime > delay) {
|
||||
func.apply(this, args);
|
||||
lastExecTime = currentTime;
|
||||
} else {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(
|
||||
() => {
|
||||
func.apply(this, args);
|
||||
lastExecTime = Date.now();
|
||||
},
|
||||
delay - (currentTime - lastExecTime),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createStyledElement(tag, styles = {}, attributes = {}) {
|
||||
const element = document.createElement(tag);
|
||||
|
||||
Object.assign(element.style, styles);
|
||||
Object.assign(element, attributes);
|
||||
|
||||
return element;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Bar Control System</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="static/main.js"></script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue