Ready. Set. Go!

This commit is contained in:
apio 2022-10-05 20:41:34 +02:00
commit f433b174cb
6 changed files with 237 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
venv/**

27
main.py Normal file
View File

@ -0,0 +1,27 @@
from flask import Flask, jsonify, render_template
from random import choice
import json
defaults = []
app = Flask(__name__)
@app.route("/")
def index():
initial_word = choice(defaults)
return render_template("index.html", initial_word=initial_word["word"], initial_image_url=initial_word["image_url"])
@app.route("/random")
def random():
word = choice(defaults)
return jsonify(word=word["word"], image_url=word["image_url"])
@app.before_first_request
def load():
global defaults
file = open("startup.json")
defaults = json.load(file)
file.close()
if __name__ == "__main__":
app.run("0.0.0.0", 8000)

10
requirements.txt Normal file
View File

@ -0,0 +1,10 @@
click==8.1.3
Flask==2.2.2
Flask-SQLAlchemy==3.0.0
greenlet==1.1.3
gunicorn==20.1.0
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.1
SQLAlchemy==1.4.41
Werkzeug==2.2.2

62
startup.json Normal file
View File

@ -0,0 +1,62 @@
[
{
"word": "batido",
"image_url": "http://www.ahungryblog.com/wp-content/uploads/2015/03/batido-de-frutas-1755x1163.jpg"
},
{
"word": "biblioteca",
"image_url": "https://cdn.theculturetrip.com/wp-content/uploads/2016/10/25584966356_8b17bbfb2c_o-min.jpg"
},
{
"word": "cacahuete",
"image_url": "https://img-3.journaldesfemmes.fr/tlg1QaE9-aR-EgiE6tAOhVcCFaU=/1500x/smart/2543bf82f3134f499c0f489b5a37e5c4/ccmcms-jdf/24583407.jpg"
},
{
"word": "hielo",
"image_url": "https://conceptodefinicion.de/wp-content/uploads/2018/05/Hielo-2.jpg"
},
{
"word": "humo",
"image_url": "https://www.pikpng.com/pngl/m/290-2900708_humo-blanco-en-for-free-download-monochrome-clipart.png"
},
{
"word": "sushi",
"image_url": "https://images.unsplash.com/photo-1607301405418-780ee5e6dd10?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1583&q=80"
},
{
"word": "huevo",
"image_url": "https://images.unsplash.com/photo-1587486913049-53fc88980cfc?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80"
},
{
"word": "hamburguesa",
"image_url": "https://images.unsplash.com/photo-1568901346375-23c9450c58cd?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=999&q=80"
},
{
"word": "rueda",
"image_url": "https://images.unsplash.com/photo-1548741465-8b453e363e48?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1074&q=80"
},
{
"word": "huerto",
"image_url": "https://images.unsplash.com/photo-1592419391068-9bd09dd58510?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80"
},
{
"word": "paella",
"image_url": "https://images.unsplash.com/photo-1588276552401-30058a0fe57b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1123&q=80"
},
{
"word": "helado",
"image_url": "https://images.unsplash.com/photo-1642646682918-442f76c1ec74?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTZ8fGhlbGFkb3xlbnwwfHwwfHw%3D&auto=format&fit=crop&w=500&q=60"
},
{
"word": "playa",
"image_url": "https://images.unsplash.com/photo-1593881135366-021cb95fd82d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1074&q=80"
},
{
"word": "volante",
"image_url": "https://images.unsplash.com/photo-1613771750144-9f2177c60fb0?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1471&q=80"
},
{
"word": "koala",
"image_url": "https://images.unsplash.com/photo-1459262838948-3e2de6c1ec80?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1469&q=80"
}
]

75
static/ortie.js Normal file
View File

@ -0,0 +1,75 @@
var target = document.getElementById("startup-target").innerText;
var buffer = "";
var successfulAttempts = 0;
var failedAttempts = 0;
var isGameActive = true;
document.body.removeChild(document.getElementById("startup-target"));
const field = document.getElementById("spell-field");
const scoreGood = document.getElementById("score-good");
const scoreBad = document.getElementById("score-bad");
const scorePercent = document.getElementById("score-percent");
const image = document.getElementById("word-image");
async function updateTarget() {
isGameActive = false;
const response = await fetch("/random");
const object = await response.json();
target = object.word;
image.src = object.image_url;
isGameActive = true;
console.log("ready!");
}
function isLetter(str) {
return str.length === 1 && str.match(/[a-z]/i);
}
updateSpellField = (text) => {
field.innerText = text;
field.style.color = "";
}
updateScores = () => {
scoreGood.innerText = successfulAttempts;
scoreBad.innerText = failedAttempts;
var total = successfulAttempts + failedAttempts;
var percent = (successfulAttempts / total) * 100;
scorePercent.innerText = Math.round(percent);
}
submitBuffer = () => {
if(buffer.toLowerCase() !== target.toLowerCase())
{
updateSpellField(target);
field.style.color = "red";
failedAttempts += 1;
} else {
updateSpellField(buffer);
field.style.color = "green";
successfulAttempts += 1;
}
updateScores();
buffer = "";
updateTarget();
}
document.onkeyup = (ev) => {
const key = ev.key;
if(isGameActive)
{
if(key === "Enter")
{
if(buffer.length != 0) submitBuffer();
}
if(isLetter(key))
{
buffer += key;
updateSpellField(buffer);
}
}
ev.preventDefault();
return false;
}

62
templates/index.html Normal file
View File

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html lang="es" class="full-page" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ortie: Entrenamiento de Ortografía</title>
<link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400&display=swap" rel="stylesheet">
<link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>
<link href="https://cdn.jsdelivr.net/npm/daisyui@2.31.0/dist/full.css" rel="stylesheet" type="text/css" />
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2/dist/tailwind.min.css" rel="stylesheet" type="text/css" />
<style>
body {
font-family: 'Source Sans Pro', sans-serif;
font-weight: 400;
}
.box {
display: flex;
align-items: center;
justify-content: center;
grid-template-columns: 1;
width: 100%;
height: 100%;
}
.full-page {
width: 100%;
height: 100%;
}
.grid-score-items {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
width: 100%;
font-size: large;
}
.score-item {
font-family: 'Source Sans Pro', sans-serif;
font-weight: 600;
}
</style>
</head>
<body class="box">
<div class="card w-96 bg-grey-200 shadow-xl">
<figure class="px-10 pt-10">
<img src="{{ initial_image_url }}" class="rounded-xl" id="word-image" />
</figure>
<div class="card-body items-center text-center">
<h2 class="card-title"><span id="spell-field">empieza!</span></h2>
<div class="mt-5"></div>
<div class="grid-score-items">
<i class="bx bx-check-circle text-green-200"><pre> </pre><span id="score-good" class="score-item">0</span></i>
<i class="bx bx-x-circle text-red-200"><pre> </pre><span id="score-bad" class="score-item">0</span></i>
<i class="bx bx-bar-chart-alt-2 text-yellow-200"><pre> </pre><span id="score-percent" class="score-item">100</span><span class="score-item">%</span></i>
</div>
</div>
</div>
<div id="startup-target">{{ initial_word }}</div>
<script src="/static/ortie.js" defer></script>
</body>
</html>