Skip to content

Instantly share code, notes, and snippets.

@dgwyer
Created February 24, 2025 14:27
Show Gist options
  • Save dgwyer/cf3332e002c94edf96d359ead363d182 to your computer and use it in GitHub Desktop.
Save dgwyer/cf3332e002c94edf96d359ead363d182 to your computer and use it in GitHub Desktop.
Audio Anki Cards
import sqlite3
# Create the SQLite database
def create_sql_questions_database():
# Connect to SQLite database (creates it if it doesn't exist)
conn = sqlite3.connect('sql_questions.db')
cursor = conn.cursor()
# Create table with auto-incrementing ID and question field
cursor.execute('''
CREATE TABLE IF NOT EXISTS sql_questions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
question TEXT NOT NULL
)
''')
# Commit the changes and close the connection
conn.commit()
conn.close()
# Add question to the database
def add_question(question_text):
conn = sqlite3.connect('sql_questions.db')
cursor = conn.cursor()
cursor.execute('INSERT INTO sql_questions (question) VALUES (?)', (question_text,))
conn.commit()
conn.close()
import sqlite3
from fasthtml.common import *
from monsterui.all import *
hdrs = (
Theme.blue.headers(),
Link(rel='stylesheet', href='styles.css', type='text/css'),
Script(src="https://unpkg.com/[email protected]"),
)
app, rt = fast_app(live=True, hdrs=hdrs)
@rt
def index():
socials = (('github','https://github.com/resolver101757'),
('twitter','https://x.com/alex_paul_kelly/'),
('linkedin','https://www.linkedin.com/in/alexpkelly/'))
return Titled("Audio Anki Cards",
Card(
H1("Welcome to the Audio Anki Cards", cls="mt-2"),
P("A simple app to add questions to a database and then use them to create audio anki cards", cls=TextPresets.muted_sm),
TableFromDicts(
header_data=['ID', 'Question', 'Actions'],
body_data=[
{'ID': q['ID'], 'Question': Span(q['Question'], id=f"question-{q['ID']}"), 'Actions': Button("Edit", cls=ButtonT.secondary, hx_get=f'/modal/{q['ID']}', hx_target="body", hx_swap="beforeend")}
for q in fetch_questions()
],
cls=(TableT.responsive, TableT.sm, TableT.divider)
),
footer=DivLAligned(*[UkIconLink(icon,href=url) for icon,url in socials]),
id="main-card",
cls="mt-4"
)
)
@rt("/modal/{qid}")
def get(qid:int):
id, question = fetch_question(qid)
return Div(
Div(_="on click trigger closeModal", cls="modal-underlay"),
Div(
H1(f"Edit Question: {qid}", cls="text-xl font-bold mb-4"),
Form(
Input(type="text",
value=question,
name="question",
autocomplete="off",
cls="w-full p-2 border rounded"),
Hidden(name="qid", value=qid),
Div(
Button("Cancel",
type="button",
_="on click trigger closeModal",
cls="btn btn-sm close"),
Button("Save",
type="submit",
cls="btn btn-sm primary"),
cls="flex justify-between gap-2 mt-4"
),
hx_put="/save-question",
hx_target=f"#question-{qid}",
_="on htmx:afterOnLoad trigger closeModal",
id="edit-form"
),
cls="modal-content"
),
id="modal", tabindex="-1",
_="""on load call me.focus()
on closeModal add .closing then wait for animationend then remove me
on keyup[key=='Escape'] trigger closeModal"""
)
def fetch_questions():
conn = sqlite3.connect('sql_questions.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM sql_questions')
questions = cursor.fetchall()
conn.close()
# Convert list of tuples to list of dictionaries
return [{'ID': q[0], 'Question': q[1]} for q in questions]
def fetch_question(id):
conn = sqlite3.connect('sql_questions.db')
cursor = conn.cursor()
cursor.execute('SELECT * FROM sql_questions WHERE id = ?', (id,))
question = cursor.fetchone()
conn.close()
return question
# Save the edited question
@rt("/save-question")
def put(qid: int, question: str):
conn = sqlite3.connect('sql_questions.db')
cursor = conn.cursor()
cursor.execute('UPDATE sql_questions SET question = ? WHERE id = ?', (question, qid))
conn.commit()
conn.close()
return question
serve()
#modal {
/* Underlay covers entire screen. */
position: fixed;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1000;
/* Flexbox centers the .modal-content vertically and horizontally */
display: flex;
flex-direction: column;
align-items: center;
/* Animate when opening */
animation-name: fadeIn;
animation-duration: 150ms;
animation-timing-function: ease;
}
#modal>.modal-underlay {
/* underlay takes up the entire viewport. This is only
required if you want to click to dismiss the popup */
position: absolute;
z-index: -1;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
#modal>.modal-content {
/* Position visible dialog near the top of the window */
margin-top: 10vh;
/* Sizing for visible dialog */
width: 80%;
max-width: 600px;
/* Display properties for visible dialog*/
border: solid 1px #999;
border-radius: 8px;
box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.3);
background-color: white;
padding: 20px;
/* Animate when opening */
animation-name: zoomIn;
animation-duration: 150ms;
animation-timing-function: ease;
}
#modal.closing {
/* Animate when closing */
animation-name: fadeOut;
animation-duration: 150ms;
animation-timing-function: ease;
}
#modal.closing>.modal-content {
/* Animate when closing */
animation-name: zoomOut;
animation-duration: 150ms;
animation-timing-function: ease;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes zoomIn {
0% {
transform: scale(0.9);
}
100% {
transform: scale(1);
}
}
@keyframes zoomOut {
0% {
transform: scale(1);
}
100% {
transform: scale(0.9);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment