From 30f209480b7563d60bfcbfe04034dbe91b7aa697 Mon Sep 17 00:00:00 2001 From: Brendan <94894839+abrendan@users.noreply.github.com> Date: Sat, 21 Sep 2024 16:54:43 +0000 Subject: [PATCH] Initial commit --- .replit | 56 +++++++++++ main.py | 33 +++++++ poetry.lock | 189 +++++++++++++++++++++++++++++++++++++ pyproject.toml | 16 ++++ replit.nix | 5 + static/css/style.css | 206 +++++++++++++++++++++++++++++++++++++++++ static/js/editor.js | 216 +++++++++++++++++++++++++++++++++++++++++++ templates/index.html | 67 ++++++++++++++ 8 files changed, 788 insertions(+) create mode 100644 .replit create mode 100644 main.py create mode 100644 poetry.lock create mode 100644 pyproject.toml create mode 100644 replit.nix create mode 100644 static/css/style.css create mode 100644 static/js/editor.js create mode 100644 templates/index.html diff --git a/.replit b/.replit new file mode 100644 index 0000000..abf0b57 --- /dev/null +++ b/.replit @@ -0,0 +1,56 @@ +modules = ["python-3.11"] + +[nix] +channel = "stable-24_05" + +[workflows] +runButton = "Project" + +[[workflows.workflow]] +name = "Project" +mode = "parallel" +author = "agent" + +[[workflows.workflow.tasks]] +task = "workflow.run" +args = "Start Flask App" + +[[workflows.workflow.tasks]] +task = "workflow.run" +args = "Flask Server" + +[[workflows.workflow]] +name = "Start Flask App" +author = "agent" + +[workflows.workflow.metadata] +agentRequireRestartOnSave = false + +[[workflows.workflow.tasks]] +task = "shell.exec" +args = "python main.py" +waitForPort = 5000 + +[[workflows.workflow]] +name = "Flask Server" +author = "agent" + +[workflows.workflow.metadata] +agentRequireRestartOnSave = false + +[[workflows.workflow.tasks]] +task = "shell.exec" +args = "python main.py" +waitForPort = 5000 + +[deployment] +run = ["sh", "-c", "python main.py"] +deploymentTarget = "cloudrun" + +[[ports]] +localPort = 80 +externalPort = 3000 + +[[ports]] +localPort = 5000 +externalPort = 80 diff --git a/main.py b/main.py new file mode 100644 index 0000000..e0ea4fa --- /dev/null +++ b/main.py @@ -0,0 +1,33 @@ +from flask import Flask, render_template, jsonify, request +import os +import chardet + +app = Flask(__name__) + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/download', methods=['POST']) +def download(): + content = request.json.get('content', '') + filename = request.json.get('filename', 'untitled.txt') + encoding = request.json.get('encoding', 'utf-8') + + # Encode the content with the specified encoding + encoded_content = content.encode(encoding) + + return jsonify({ + 'content': encoded_content.decode('utf-8'), # Send as UTF-8 for JSON + 'filename': filename, + 'encoding': encoding + }) + +@app.route('/detect_encoding', methods=['POST']) +def detect_encoding(): + file_content = request.json.get('content', '') + result = chardet.detect(file_content.encode('utf-8')) + return jsonify({'encoding': result['encoding']}) + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..eec8d85 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,189 @@ +# This file is automatically @generated by Poetry 1.5.5 and should not be changed by hand. + +[[package]] +name = "blinker" +version = "1.8.2" +description = "Fast, simple object-to-object and broadcast signaling" +optional = false +python-versions = ">=3.8" +files = [ + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, +] + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "flask" +version = "3.0.3" +description = "A simple framework for building complex web applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, + {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, +] + +[package.dependencies] +blinker = ">=1.6.2" +click = ">=8.1.3" +itsdangerous = ">=2.1.2" +Jinja2 = ">=3.1.2" +Werkzeug = ">=3.0.0" + +[package.extras] +async = ["asgiref (>=3.2)"] +dotenv = ["python-dotenv"] + +[[package]] +name = "itsdangerous" +version = "2.2.0" +description = "Safely pass data to untrusted environments and back." +optional = false +python-versions = ">=3.8" +files = [ + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "werkzeug" +version = "3.0.4" +description = "The comprehensive WSGI web application library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c"}, + {file = "werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog (>=2.3)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.11" +content-hash = "0aa5e96be856ef6b55736b8fffc2e5263f5c9bbd05f4fb47d03fd94583d1d9ed" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..148fbd7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "repl-nix-uwpnotepadpro" +version = "0.1.0" +description = "" +authors = ["Your Name "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +flask = "^3.0.3" +chardet = "^5.2.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/replit.nix b/replit.nix new file mode 100644 index 0000000..404c2dd --- /dev/null +++ b/replit.nix @@ -0,0 +1,5 @@ +{pkgs}: { + deps = [ + pkgs.postgresql + ]; +} diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000..2140f5a --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,206 @@ +body { + font-family: 'Segoe UI', Arial, sans-serif; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + height: 100vh; + background-color: #1e1e1e; + color: #ffffff; +} + +.menu-bar { + background-color: #2d2d2d; + padding: 10px; + border-bottom: 1px solid #3a3a3a; + display: flex; + align-items: center; + flex-wrap: wrap; +} + +.menu-item { + display: inline-flex; + align-items: center; + margin-right: 20px; + cursor: pointer; + color: #ffffff; + font-size: 14px; + text-decoration: none; +} + +.menu-item:hover { + color: #0078d4; +} + +.notepad-icon { + margin-right: 5px; +} + +.notepad-icon.logo { + width: 24px; + height: 24px; +} + +#brendanLink { + margin-right: 20px; +} + +#brendanLink:hover { + color: #0078d4; +} + +#encodingSelect, #fontSelect { + background-color: #3c3c3c; + color: #ffffff; + border: 1px solid #555555; + padding: 5px 10px; + font-size: 14px; + cursor: pointer; + outline: none; + transition: background-color 0.3s, border-color 0.3s; +} + +#encodingSelect:hover, #encodingSelect:focus, +#fontSelect:hover, #fontSelect:focus { + background-color: #4c4c4c; + border-color: #0078d4; +} + +#encodingSelect option, #fontSelect option { + background-color: #3c3c3c; + color: #ffffff; +} + +#editor { + flex-grow: 1; + width: 100%; + padding: 20px; + box-sizing: border-box; + border: none; + resize: none; + font-size: 14px; + line-height: 1.6; + background-color: #252526; + color: #d4d4d4; + white-space: pre; + overflow-wrap: normal; + overflow-x: auto; + font-family: Consolas, 'Courier New', Monaco, 'Roboto Mono', Arial, Verdana, 'Times New Roman', Georgia, Palatino, Wingdings, monospace; +} + +#editor.wrap { + white-space: pre-wrap; + overflow-wrap: break-word; + overflow-x: hidden; +} + +#editor:focus { + outline: none; +} + +.modal { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.6); +} + +.modal-content { + background-color: #2d2d2d; + margin: 15% auto; + padding: 20px; + border: 1px solid #3a3a3a; + width: 80%; + max-width: 500px; + box-shadow: 0 4px 8px rgba(0,0,0,0.2); +} + +.close { + color: #999999; + float: right; + font-size: 28px; + font-weight: bold; + cursor: pointer; +} + +.close:hover, +.close:focus { + color: #ffffff; + text-decoration: none; +} + +#findInput { + width: 100%; + padding: 10px; + margin-bottom: 10px; + background-color: #3c3c3c; + border: 1px solid #555555; + color: #ffffff; + font-size: 14px; +} + +#findButton { + padding: 10px 20px; + background-color: #0078d4; + border: none; + color: #ffffff; + cursor: pointer; + font-size: 14px; + transition: background-color 0.3s; +} + +#findButton:hover { + background-color: #2b90d9; +} + +#printBtn { + transition: color 0.3s; +} + +#printBtn:hover { + color: #0078d4; +} + +#wrapText { + margin-right: 5px; +} + +/* Brendan Modal Styles */ +#brendanModal .modal-content { + text-align: center; +} + +.brendan-logo { + width: 48px; + height: 48px; + margin-bottom: 15px; +} + +.brendan-description { + font-size: 16px; + margin-bottom: 10px; +} + +.brendan-byline { + font-style: italic; + margin-bottom: 15px; +} + +.brendan-link { + display: inline-block; + padding: 10px 20px; + background-color: #0078d4; + color: #ffffff; + text-decoration: none; + border-radius: 4px; + transition: background-color 0.3s; +} + +.brendan-link:hover { + background-color: #2b90d9; +} diff --git a/static/js/editor.js b/static/js/editor.js new file mode 100644 index 0000000..1a83bb3 --- /dev/null +++ b/static/js/editor.js @@ -0,0 +1,216 @@ +document.addEventListener('DOMContentLoaded', function() { + console.log("DOM content loaded"); + const editor = document.getElementById('editor'); + const openBtn = document.getElementById('openBtn'); + const saveBtn = document.getElementById('saveBtn'); + const findBtn = document.getElementById('findBtn'); + const printBtn = document.getElementById('printBtn'); + const modal = document.getElementById('modal'); + const closeModal = document.getElementsByClassName('close')[0]; + const findInput = document.getElementById('findInput'); + const findButton = document.getElementById('findButton'); + const encodingSelect = document.getElementById('encodingSelect'); + const fontSelect = document.getElementById('fontSelect'); + const wrapTextCheckbox = document.getElementById('wrapText'); + const fileInput = document.getElementById('fileInput'); + + // Brendan Modal elements + const brendanLink = document.getElementById('brendanLink'); + const brendanModal = document.getElementById('brendanModal'); + const closeBrendanModal = brendanModal.getElementsByClassName('close')[0]; + + console.log("All elements selected"); + + let currentFileName = 'untitled.txt'; + let currentEncoding = 'utf-8'; + + // Set file input to accept only .txt files + fileInput.setAttribute('accept', '.txt'); + + openBtn.addEventListener('click', function() { + console.log("Open button clicked"); + fileInput.click(); + }); + + fileInput.addEventListener('change', function(e) { + console.log("File input changed"); + const file = e.target.files[0]; + if (file) { + if (file.name.toLowerCase().endsWith('.txt')) { + currentFileName = file.name; + const reader = new FileReader(); + reader.onload = function(e) { + const content = e.target.result; + detectEncoding(content); + editor.value = content; + console.log("File loaded successfully"); + }; + reader.onerror = function(e) { + console.error("Error reading file:", e); + alert("An error occurred while reading the file. Please try again."); + }; + reader.readAsText(file); + } else { + alert("Please select a .txt file."); + fileInput.value = ''; // Clear the file input + } + } + }); + + saveBtn.addEventListener('click', function() { + console.log("Save button clicked"); + const content = editor.value; + fetch('/download', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ content: content, filename: currentFileName, encoding: currentEncoding }), + }) + .then(response => response.json()) + .then(data => { + const blob = new Blob([data.content], { type: 'text/plain' }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + a.href = url; + a.download = data.filename; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + console.log("File saved successfully"); + }) + .catch((error) => { + console.error('Error:', error); + alert("An error occurred while saving the file. Please try again."); + }); + }); + + findBtn.addEventListener('click', function() { + console.log("Find button clicked"); + modal.style.display = "block"; + }); + + closeModal.addEventListener('click', function() { + modal.style.display = "none"; + }); + + window.addEventListener('click', function(event) { + if (event.target == modal) { + modal.style.display = "none"; + } + }); + + findButton.addEventListener('click', function() { + console.log("Find text button clicked"); + const searchText = findInput.value; + if (searchText) { + const content = editor.value; + const startIndex = content.indexOf(searchText); + if (startIndex !== -1) { + editor.setSelectionRange(startIndex, startIndex + searchText.length); + editor.focus(); + console.log("Text found and highlighted"); + } else { + alert("Text not found!"); + } + } + }); + + encodingSelect.addEventListener('change', function() { + console.log("Encoding changed to:", this.value); + currentEncoding = this.value; + }); + + function detectEncoding(content) { + console.log("Detecting encoding"); + fetch('/detect_encoding', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ content: content }), + }) + .then(response => response.json()) + .then(data => { + currentEncoding = data.encoding; + encodingSelect.value = currentEncoding; + console.log("Encoding detected:", currentEncoding); + }) + .catch((error) => { + console.error('Error:', error); + alert("An error occurred while detecting the file encoding. Using default encoding."); + }); + } + + // Print functionality + printBtn.addEventListener('click', function() { + console.log("Print button clicked"); + const content = editor.value; + const printWindow = window.open('', '_blank'); + printWindow.document.write('Print'); + printWindow.document.write(''); + printWindow.document.write(''); + printWindow.document.write(content); + printWindow.document.write(''); + printWindow.document.close(); + printWindow.print(); + }); + + // Basic text editing features + document.addEventListener('keydown', function(e) { + if (e.ctrlKey || e.metaKey) { + switch (e.key.toLowerCase()) { + case 'x': + document.execCommand('cut'); + break; + case 'c': + document.execCommand('copy'); + break; + case 'v': + document.execCommand('paste'); + break; + } + } + }); + + // Font selection + fontSelect.addEventListener('change', function() { + console.log("Font changed to:", this.value); + editor.style.fontFamily = this.value + ', monospace'; + }); + + // Text wrapping + wrapTextCheckbox.addEventListener('change', function() { + console.log("Text wrap changed to:", this.checked); + if (this.checked) { + editor.classList.add('wrap'); + } else { + editor.classList.remove('wrap'); + } + }); + + // Set initial font + editor.style.fontFamily = fontSelect.value + ', monospace'; + + // Brendan Modal functionality + brendanLink.addEventListener('click', function(e) { + console.log("Brendan link clicked"); + e.preventDefault(); + brendanModal.style.display = "block"; + }); + + closeBrendanModal.addEventListener('click', function() { + brendanModal.style.display = "none"; + }); + + window.addEventListener('click', function(event) { + if (event.target == brendanModal) { + brendanModal.style.display = "none"; + } + }); + + console.log("All event listeners set up"); +}); + +console.log("editor.js loaded"); diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..ef0a23d --- /dev/null +++ b/templates/index.html @@ -0,0 +1,67 @@ + + + + + + V_EditorWeb + + + + + + + + + + + + +