diff --git a/todos/django/Pipfile b/todos/django/Pipfile new file mode 100644 index 0000000..d040849 --- /dev/null +++ b/todos/django/Pipfile @@ -0,0 +1,18 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +django = "*" + +[dev-packages] +"flake8" = "*" +"flake8-django" = "*" +"autopep8" = "*" + +[requires] +python_version = "3.6" + +[scripts] +start = "django-admin runserver --pythonpath=. --settings=todomvp" diff --git a/todos/django/Pipfile.lock b/todos/django/Pipfile.lock new file mode 100644 index 0000000..d9145b2 --- /dev/null +++ b/todos/django/Pipfile.lock @@ -0,0 +1,81 @@ +{ + "_meta": { + "hash": { + "sha256": "7faae15d2b677edd6ad93507f7316e0b566cfa0ae521694e2750cc2585e62f9b" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "django": { + "hashes": [ + "sha256:1ffab268ada3d5684c05ba7ce776eaeedef360712358d6a6b340ae9f16486916", + "sha256:dd46d87af4c1bf54f4c926c3cfa41dc2b5c15782f15e4329752ce65f5dad1c37" + ], + "index": "pypi", + "version": "==2.1.3" + }, + "pytz": { + "hashes": [ + "sha256:31cb35c89bd7d333cd32c5f278fca91b523b0834369e757f4c5641ea252236ca", + "sha256:8e0f8568c118d3077b46be7d654cc8167fa916092e28320cde048e54bfc9f1e6" + ], + "version": "==2018.7" + } + }, + "develop": { + "autopep8": { + "hashes": [ + "sha256:33d2b5325b7e1afb4240814fe982eea3a92ebea712869bfd08b3c0393404248c" + ], + "index": "pypi", + "version": "==1.4.3" + }, + "flake8": { + "hashes": [ + "sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670", + "sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2" + ], + "index": "pypi", + "version": "==3.6.0" + }, + "flake8-django": { + "hashes": [ + "sha256:44ae68fe251a7affd39445acc78965d48f86bf37a04f5f647eba318cac1d29e4", + "sha256:af4b240de5a8bac27ea2596b9b4860aad052922fa8a347e28d09a898fee29f42" + ], + "index": "pypi", + "version": "==0.0.3" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83", + "sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a" + ], + "version": "==2.4.0" + }, + "pyflakes": { + "hashes": [ + "sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49", + "sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae" + ], + "version": "==2.0.0" + } + } +} diff --git a/todos/django/static/check.svg b/todos/django/static/check.svg new file mode 100644 index 0000000..2df5dee --- /dev/null +++ b/todos/django/static/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/django/static/plus.svg b/todos/django/static/plus.svg new file mode 100644 index 0000000..23c27d8 --- /dev/null +++ b/todos/django/static/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/django/static/tick.png b/todos/django/static/tick.png new file mode 100644 index 0000000..71fb4ad Binary files /dev/null and b/todos/django/static/tick.png differ diff --git a/todos/django/static/todo.css b/todos/django/static/todo.css new file mode 100644 index 0000000..a4594b7 --- /dev/null +++ b/todos/django/static/todo.css @@ -0,0 +1,153 @@ +:root { + --text-color: rgb(20,20,20); + --border-color: black; + --title-color: rgb(60,60,60); + --done-color: rgb(200,200,200); + --background-color: white; + box-sizing: border-box; + padding: 0; + margin: 0; +} + +body { + min-height: 100vh; + padding: 0; + align-content: center; + margin: 0; + font-family: sans-serif; + line-height: 1.3rem; + font-size: 24px; + + background-color: var(--background-color); + color: var(--text-color); +} + +label { + font-size: 0.8rem; +} + +input { + box-sizing: border-box; + border: var(--border-color) solid 2px; + background-color: var(--background-color); +} + +section { + padding: 1.5rem; + margin-left: auto; + margin-right: auto; + max-width: 40rem; +} + +.new-todo form { + display: grid; + grid-template-columns: auto 29px; + grid-template-rows: auto; + column-gap: 1rem; +} + +.new-todo label[for="new-item"] { + grid-row: 1 / span 1; + grid-column: 1 / span 2; + margin: auto 1rem; +} + +.new-todo input#new-item { + grid-row: 1 / span 1; + grid-column: 1 / span 1; + padding: 0.5rem; + font-size: 1rem; +} + +.new-todo form input#add-new-item { + grid-row: 1 / span 1; + grid-column: 2 / span 1; + margin: auto; +} + +.button-container { + float: right; + display: flex; + flex-direction: column; + height: 100%; +} + +ul { + margin: 0; + padding: 0; +} + +ul:empty::after { + content: "You've not added any todos to the list. Use the box above to add a new todo."; + font-size: 1rem; + margin: 1rem; + font-style: italic; + border: 2px dotted black; + padding: 0.5rem; + display: block; + text-align: justify; + text-align-last: center; +} + +li { + display: flex; + border-bottom: 1px dotted var(--border-color); +} + +li:last-child { + border-bottom: none; +} + +li .item-name { + flex: auto; + margin: auto; + padding: 0 1rem; +} + +li form input, +.new-todo form input#add-new-item { + width: 30px; + height: 30px; + padding: 0; + + background-repeat: no-repeat; + background-size: contain; + background-position: center; + + /* hide text */ + text-indent: 100%; + white-space: nowrap; + overflow: hidden; +} + +.todo form input { + margin: 1em; +} + +.todo form input.delete { + background-image: url('trashcan.svg'); + border: none; +} +input#add-new-item { background-image: url('plus.svg'); } +.todo form input.complete { background-image: none; } +.todo form input.uncomplete { background-image: url('check.svg'); } + +.done { + color: var(--done-color); +} + +.todo form { + display: contents; +} + +h1 { + font-weight: 200; + color: var(--title-color); + margin: 2rem; + display: none; +} + +h2 { + border-bottom: 1px solid black; + padding: 0 0 1rem 1rem; +} diff --git a/todos/django/static/trashcan.svg b/todos/django/static/trashcan.svg new file mode 100644 index 0000000..3d8c051 --- /dev/null +++ b/todos/django/static/trashcan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/django/static/x.svg b/todos/django/static/x.svg new file mode 100644 index 0000000..e377314 --- /dev/null +++ b/todos/django/static/x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/django/templates/home.html b/todos/django/templates/home.html new file mode 100644 index 0000000..5edd943 --- /dev/null +++ b/todos/django/templates/home.html @@ -0,0 +1,75 @@ +{% load static %} + + + + Todo MVP + + + + +

Todo MVP

+
+
+ + +
+
+ +
+

Todo list

+ +
+ + diff --git a/todos/django/todomvp/__init__.py b/todos/django/todomvp/__init__.py new file mode 100644 index 0000000..de30fa2 --- /dev/null +++ b/todos/django/todomvp/__init__.py @@ -0,0 +1,38 @@ +# Note: I am manually creating a tiny project here since Django is much more +# powerful and a bit too much of a powerhouse for this tiny project ;) +# Django's new project command adds a whole lot more stuff that make sense for a +# typical server, but not here. +import os + +from todomvp.views import IndexView, todo_done, todo_undone, todo_delete +from django.urls import path + +DEBUG = True +SECRET_KEY = '4l0ngs3cr3tstr1ngw3lln0ts0l0ngw41tn0w1tsl0ng3n0ugh' +ROOT_URLCONF = __name__ +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, "templates")] + }, +] + +INSTALLED_APPS = [ + "django.contrib.staticfiles" +] + +STATIC_URL = "/static/" +STATICFILES_FINDERS = [ + 'django.contrib.staticfiles.finders.FileSystemFinder' +] +STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "static") +] + +urlpatterns = [ + path("", IndexView.as_view(), name="index"), + path("done", todo_done, name="done"), + path("not-done", todo_undone, name="not-done"), + path("delete", todo_delete, name="delete") +] diff --git a/todos/django/todomvp/views.py b/todos/django/todomvp/views.py new file mode 100644 index 0000000..cc7ce2e --- /dev/null +++ b/todos/django/todomvp/views.py @@ -0,0 +1,62 @@ +from django.http import HttpResponse +from django.shortcuts import redirect, reverse +from django.views.generic import TemplateView +from django.views.generic.base import View + +todos = [] + + +def get_next_id() -> int: + """WARNING: Not thread-safe, and shouldn't be used in production. I'm + basically mimicking basic DB utility functions since I don't have any. + + Use a DB, and use their utility functions!""" + if len(todos) == 0: + return 0 + else: + return max([t["id"] for t in todos]) + 1 + +def get_todo_index(request): + return [t["id"] for t in todos].index(int(request.POST.get("item"))) + + +class IndexView(TemplateView): + # If GET, will render template. If POST, will use the post function below. + # All other methods aren't allowed. + template_name = "home.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["todos"] = todos + return context + + def post(self, request, *args, **kwargs): + todo = { + "id": get_next_id(), + "name": request.POST.get("item"), + "done": False + } + todos.append(todo) + + return redirect(reverse("index")) + + +def todo_done(request): + if request.method == "POST": + idx = get_todo_index(request) + todos[idx]["done"] = True + return redirect(reverse("index")) + + +def todo_undone(request): + if request.method == "POST": + idx = get_todo_index(request) + todos[idx]["done"] = False + return redirect(reverse("index")) + + +def todo_delete(request): + if request.method == "POST": + idx = get_todo_index(request) + del todos[idx] + return redirect(reverse("index")) diff --git a/todos/flask/.env b/todos/flask/.env new file mode 100644 index 0000000..3904141 --- /dev/null +++ b/todos/flask/.env @@ -0,0 +1,9 @@ +# dotenvs get automatically applied by pipenv when running scripts or dropping +# into virtualenv shell +FLASK_SKIP_DOTENV=1 +FLASK_DEBUG=1 +FLASK_RUN_IP=0.0.0.0 +FLASK_RUN_PORT=3000 +FLASK_ENV=development +FLASK_APP=todomvp +FLASK_SECRET=fcd3f4b28b12b75488c3305222d7fd20 diff --git a/todos/flask/Pipfile b/todos/flask/Pipfile new file mode 100644 index 0000000..ef99c0b --- /dev/null +++ b/todos/flask/Pipfile @@ -0,0 +1,17 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +flask = "*" + +[dev-packages] +"flake8" = "*" +"autopep8" = "*" + +[requires] +python_version = "3.6" + +[scripts] +start = "flask run" diff --git a/todos/flask/Pipfile.lock b/todos/flask/Pipfile.lock new file mode 100644 index 0000000..cc1b954 --- /dev/null +++ b/todos/flask/Pipfile.lock @@ -0,0 +1,127 @@ +{ + "_meta": { + "hash": { + "sha256": "cef3e31ae481a675c82aa02c4c343d754358189b5dea415e042a3395a787e6d4" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "click": { + "hashes": [ + "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", + "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" + ], + "version": "==7.0" + }, + "flask": { + "hashes": [ + "sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48", + "sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05" + ], + "index": "pypi", + "version": "==1.0.2" + }, + "itsdangerous": { + "hashes": [ + "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", + "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" + ], + "version": "==1.1.0" + }, + "jinja2": { + "hashes": [ + "sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd", + "sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4" + ], + "version": "==2.10" + }, + "markupsafe": { + "hashes": [ + "sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432", + "sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b", + "sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9", + "sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af", + "sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834", + "sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd", + "sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d", + "sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7", + "sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b", + "sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3", + "sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c", + "sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2", + "sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7", + "sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36", + "sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1", + "sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e", + "sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1", + "sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c", + "sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856", + "sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550", + "sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492", + "sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672", + "sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401", + "sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6", + "sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6", + "sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c", + "sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd", + "sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1" + ], + "version": "==1.1.0" + }, + "werkzeug": { + "hashes": [ + "sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c", + "sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b" + ], + "version": "==0.14.1" + } + }, + "develop": { + "autopep8": { + "hashes": [ + "sha256:33d2b5325b7e1afb4240814fe982eea3a92ebea712869bfd08b3c0393404248c" + ], + "index": "pypi", + "version": "==1.4.3" + }, + "flake8": { + "hashes": [ + "sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670", + "sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2" + ], + "index": "pypi", + "version": "==3.6.0" + }, + "mccabe": { + "hashes": [ + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + ], + "version": "==0.6.1" + }, + "pycodestyle": { + "hashes": [ + "sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83", + "sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a" + ], + "version": "==2.4.0" + }, + "pyflakes": { + "hashes": [ + "sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49", + "sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae" + ], + "version": "==2.0.0" + } + } +} diff --git a/todos/flask/todomvp/__init__.py b/todos/flask/todomvp/__init__.py new file mode 100644 index 0000000..358683a --- /dev/null +++ b/todos/flask/todomvp/__init__.py @@ -0,0 +1,11 @@ +import os + +from flask import Flask + +app = Flask(__name__) +app.config["SECRET_KEY"] = os.environ.get("FLASK_SECRET") + +from todomvp import routes + +if __name__ == "__main__": + app.run(debug=bool(os.environ.get("FLASK_DEBUG"))) diff --git a/todos/flask/todomvp/routes.py b/todos/flask/todomvp/routes.py new file mode 100644 index 0000000..2d06b23 --- /dev/null +++ b/todos/flask/todomvp/routes.py @@ -0,0 +1,54 @@ +from flask import render_template, redirect, url_for +from flask.globals import request +from todomvp import app + +todos = [] + +def get_next_id() -> int: + """WARNING: Not thread-safe, and shouldn't be used in production. I'm + basically mimicking basic DB utility functions since I don't have any. + + Use a DB, and use their utility functions!""" + if len(todos) == 0: + return 0 + else: + return max([t["id"] for t in todos]) + 1 + + +@app.route("/", methods=["GET", "POST"]) +def index(): + if request.method == "POST": + todo = { + "id": get_next_id(), + "name": request.form.get("item"), + "done": False + } + todos.append(todo) + + return render_template("home.html", todos=todos) + + + +def get_todo_index() -> int: + return [t["id"] for t in todos].index(int(request.form.get("item"))) + + +@app.route("/done", methods=["POST"]) +def done(): + idx = get_todo_index() + todos[idx]["done"] = True + return redirect(url_for("index")) + + +@app.route("/not-done", methods=["POST"]) +def not_done(): + idx = get_todo_index() + todos[idx]["done"] = False + return redirect(url_for("index")) + + +@app.route("/delete", methods=["POST"]) +def delete(): + idx = get_todo_index() + del todos[idx] + return redirect(url_for("index")) diff --git a/todos/flask/todomvp/static/check.svg b/todos/flask/todomvp/static/check.svg new file mode 100644 index 0000000..2df5dee --- /dev/null +++ b/todos/flask/todomvp/static/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/flask/todomvp/static/plus.svg b/todos/flask/todomvp/static/plus.svg new file mode 100644 index 0000000..23c27d8 --- /dev/null +++ b/todos/flask/todomvp/static/plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/flask/todomvp/static/tick.png b/todos/flask/todomvp/static/tick.png new file mode 100644 index 0000000..71fb4ad Binary files /dev/null and b/todos/flask/todomvp/static/tick.png differ diff --git a/todos/flask/todomvp/static/todo.css b/todos/flask/todomvp/static/todo.css new file mode 100644 index 0000000..a4594b7 --- /dev/null +++ b/todos/flask/todomvp/static/todo.css @@ -0,0 +1,153 @@ +:root { + --text-color: rgb(20,20,20); + --border-color: black; + --title-color: rgb(60,60,60); + --done-color: rgb(200,200,200); + --background-color: white; + box-sizing: border-box; + padding: 0; + margin: 0; +} + +body { + min-height: 100vh; + padding: 0; + align-content: center; + margin: 0; + font-family: sans-serif; + line-height: 1.3rem; + font-size: 24px; + + background-color: var(--background-color); + color: var(--text-color); +} + +label { + font-size: 0.8rem; +} + +input { + box-sizing: border-box; + border: var(--border-color) solid 2px; + background-color: var(--background-color); +} + +section { + padding: 1.5rem; + margin-left: auto; + margin-right: auto; + max-width: 40rem; +} + +.new-todo form { + display: grid; + grid-template-columns: auto 29px; + grid-template-rows: auto; + column-gap: 1rem; +} + +.new-todo label[for="new-item"] { + grid-row: 1 / span 1; + grid-column: 1 / span 2; + margin: auto 1rem; +} + +.new-todo input#new-item { + grid-row: 1 / span 1; + grid-column: 1 / span 1; + padding: 0.5rem; + font-size: 1rem; +} + +.new-todo form input#add-new-item { + grid-row: 1 / span 1; + grid-column: 2 / span 1; + margin: auto; +} + +.button-container { + float: right; + display: flex; + flex-direction: column; + height: 100%; +} + +ul { + margin: 0; + padding: 0; +} + +ul:empty::after { + content: "You've not added any todos to the list. Use the box above to add a new todo."; + font-size: 1rem; + margin: 1rem; + font-style: italic; + border: 2px dotted black; + padding: 0.5rem; + display: block; + text-align: justify; + text-align-last: center; +} + +li { + display: flex; + border-bottom: 1px dotted var(--border-color); +} + +li:last-child { + border-bottom: none; +} + +li .item-name { + flex: auto; + margin: auto; + padding: 0 1rem; +} + +li form input, +.new-todo form input#add-new-item { + width: 30px; + height: 30px; + padding: 0; + + background-repeat: no-repeat; + background-size: contain; + background-position: center; + + /* hide text */ + text-indent: 100%; + white-space: nowrap; + overflow: hidden; +} + +.todo form input { + margin: 1em; +} + +.todo form input.delete { + background-image: url('trashcan.svg'); + border: none; +} +input#add-new-item { background-image: url('plus.svg'); } +.todo form input.complete { background-image: none; } +.todo form input.uncomplete { background-image: url('check.svg'); } + +.done { + color: var(--done-color); +} + +.todo form { + display: contents; +} + +h1 { + font-weight: 200; + color: var(--title-color); + margin: 2rem; + display: none; +} + +h2 { + border-bottom: 1px solid black; + padding: 0 0 1rem 1rem; +} diff --git a/todos/flask/todomvp/static/trashcan.svg b/todos/flask/todomvp/static/trashcan.svg new file mode 100644 index 0000000..3d8c051 --- /dev/null +++ b/todos/flask/todomvp/static/trashcan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/flask/todomvp/static/x.svg b/todos/flask/todomvp/static/x.svg new file mode 100644 index 0000000..e377314 --- /dev/null +++ b/todos/flask/todomvp/static/x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/todos/flask/todomvp/templates/home.html b/todos/flask/todomvp/templates/home.html new file mode 100644 index 0000000..60ffc66 --- /dev/null +++ b/todos/flask/todomvp/templates/home.html @@ -0,0 +1,74 @@ + + + + Todo MVP + + + + +

Todo MVP

+
+
+ + +
+
+ +
+

Todo list

+ +
+ +