Compare commits

..

8 Commits

Author SHA1 Message Date
Sergio Martínez Portela
2f3c52f5f2 Push notes section to the top. 2024-07-21 19:54:23 +02:00
Sergio Martínez Portela
d630fb0f70 Add Malleable Software slides to homepage. 2024-07-21 19:48:23 +02:00
Sergio Martínez Portela
ce35091852 Add configurable subpath. 2024-05-05 12:29:26 +02:00
Sergio Martínez Portela
d9b85c8475 Fix height of arrows on external links. 2024-03-12 01:40:26 +01:00
Sergio Martínez Portela
9a020285ad Add clean styling for SOMETIME state. 2024-03-10 17:51:58 +01:00
Sergio Martínez Portela
e639df35a7 s/Mastodon/ActivityPub/ 2023-11-12 15:34:44 +01:00
Sergio Martínez Portela
89e50a6310 Fix color scheme on dark mode. 2023-11-01 23:37:57 +01:00
Sergio Martínez Portela
28122c3c31 Use dark-syntax.css only when dark mode is selected. 2023-10-05 08:53:50 +02:00
5 changed files with 146 additions and 149 deletions

View File

@ -22,7 +22,6 @@ import shutil
import traceback import traceback
import time import time
import re import re
import sqlite3
from typing import List from typing import List
from bs4 import BeautifulSoup as bs4 from bs4 import BeautifulSoup as bs4
@ -64,7 +63,6 @@ JINJA_ENV = jinja2.Environment(
autoescape=jinja2.select_autoescape() autoescape=jinja2.select_autoescape()
) )
PARSER_NAMESPACE = 'codigoparallevar.com/blog'
WATCH = True WATCH = True
if os.getenv('WATCH_AND_REBUILD', '1') == '0': if os.getenv('WATCH_AND_REBUILD', '1') == '0':
WATCH = False WATCH = False
@ -178,12 +176,6 @@ def get_out_path(front_matter):
return out_path return out_path
def create_db(path):
db = sqlite3.connect(path)
db.execute('CREATE VIRTUAL TABLE IF NOT EXISTS note_search USING fts5(note_id, title, body, top_level_title, is_done, is_todo, parser_namespace, url, tokenize="trigram");')
db.execute('DELETE FROM note_search WHERE parser_namespace = ?;', (PARSER_NAMESPACE,))
return db
def load_all(top_dir_relative): def load_all(top_dir_relative):
top = os.path.abspath(top_dir_relative) top = os.path.abspath(top_dir_relative)
@ -464,39 +456,10 @@ def render_rss(docs, dest_top):
f.write(result) f.write(result)
def regen_all(source_top, dest_top, docs=None, db=None): def regen_all(source_top, dest_top, docs=None):
if docs is None: if docs is None:
docs = load_all(source_top) docs = load_all(source_top)
cur = db.cursor()
cleaned_db = False
try:
cur.execute('DELETE FROM note_search WHERE parser_namespace = ?;', (PARSER_NAMESPACE,))
cleaned_db = True
except sqlite3.OperationalError as err:
if WATCH:
logging.warning("Error pre-cleaning DB, search won't be updated")
else:
raise
# Save posts to DB
for (doc, front_matter, out_path) in docs.values():
cur.execute('''INSERT INTO note_search(note_id, title, body, top_level_title, is_done, is_todo, parser_namespace, url) VALUES (?, ?, ?, ?, ?, ?, ?, ?);''',
(
out_path,
front_matter['title'],
doc,
front_matter['title'],
False,
False,
PARSER_NAMESPACE,
out_path + '/index.html',
))
cur.close()
db.commit()
# Render posts # Render posts
for (doc, front_matter, out_path) in docs.values(): for (doc, front_matter, out_path) in docs.values():
doc_full_path = os.path.join(dest_top, out_path) doc_full_path = os.path.join(dest_top, out_path)
@ -550,8 +513,7 @@ def main(source_top, dest_top):
## Initial load ## Initial load
t0 = time.time() t0 = time.time()
logging.info("Initial load...") logging.info("Initial load...")
db = create_db(os.path.join(dest_top, '..', 'db.sqlite3')) docs = regen_all(source_top, dest_top)
docs = regen_all(source_top, dest_top, db=db)
logging.info("Initial load completed in {:.2f}s".format(time.time() - t0)) logging.info("Initial load completed in {:.2f}s".format(time.time() - t0))
if not WATCH: if not WATCH:
@ -595,7 +557,7 @@ def main(source_top, dest_top):
if is_static_resource: if is_static_resource:
logging.info("Updated static resources in {:.2f}s".format(time.time() - t0)) logging.info("Updated static resources in {:.2f}s".format(time.time() - t0))
else: else:
docs = regen_all(source_top, dest_top, docs, db=db) docs = regen_all(source_top, dest_top, docs)
logging.info("Updated all in {:.2f}s".format(time.time() - t0)) logging.info("Updated all in {:.2f}s".format(time.time() - t0))
else: else:

View File

@ -46,14 +46,14 @@ IMG_EXTENSIONS = set([
"gif", "gif",
]) ])
SKIPPED_TAGS = set(['attach']) SKIPPED_TAGS = set(['attach'])
PARSER_NAMESPACE = 'codigoparallevar.com/notes' DEFAULT_SUBPATH = "public"
WATCH = True WATCH = True
if os.getenv('WATCH_AND_REBUILD', '1') == '0': if os.getenv('WATCH_AND_REBUILD', '1') == '0':
WATCH = False WATCH = False
MIN_HIDDEN_HEADLINE_LEVEL = 2 MIN_HIDDEN_HEADLINE_LEVEL = 2
INDEX_ID = "ea48ec1d-f9d4-4fb7-b39a-faa7b6e2ba95" INDEX_ID = os.getenv("INDEX_ID", "ea48ec1d-f9d4-4fb7-b39a-faa7b6e2ba95")
SITE_NAME = "Código para llevar" SITE_NAME = "Código para llevar"
MONITORED_EVENT_TYPES = ( MONITORED_EVENT_TYPES = (
@ -89,9 +89,11 @@ def is_git_path(path):
return any([chunk == ".git" for chunk in path.split(os.sep)]) return any([chunk == ".git" for chunk in path.split(os.sep)])
def create_db(path): def create_db(path):
if os.path.exists(path):
os.unlink(path)
db = sqlite3.connect(path) db = sqlite3.connect(path)
db.execute('CREATE VIRTUAL TABLE IF NOT EXISTS note_search USING fts5(note_id, title, body, top_level_title, is_done, is_todo, parser_namespace, url tokenize="trigram");') db.execute('CREATE VIRTUAL TABLE note_search USING fts5(note_id, title, body, top_level_title, is_done, is_todo, tokenize="trigram");')
db.execute('DELETE FROM note_search WHERE parser_namespace = ?;', (PARSER_NAMESPACE,))
return db return db
def load_all(top_dir_relative): def load_all(top_dir_relative):
@ -119,13 +121,13 @@ def load_all(top_dir_relative):
logging.info("Collected {} files".format(len(docs))) logging.info("Collected {} files".format(len(docs)))
return docs return docs
def regen_all(src_top, dest_top, *, docs=None, db=None): def regen_all(src_top, dest_top, subpath, *, docs=None, db=None):
files_generated = 0 files_generated = 0
cur = db.cursor() cur = db.cursor()
cleaned_db = False cleaned_db = False
try: try:
cur.execute('DELETE FROM note_search WHERE parser_namespace = ?;', (PARSER_NAMESPACE,)) cur.execute('DELETE FROM note_search;')
cleaned_db = True cleaned_db = True
except sqlite3.OperationalError as err: except sqlite3.OperationalError as err:
if WATCH: if WATCH:
@ -149,7 +151,7 @@ def regen_all(src_top, dest_top, *, docs=None, db=None):
changed = False changed = False
headlines = list(doc.getAllHeadlines()) headlines = list(doc.getAllHeadlines())
related = None related = None
if not relpath.startswith("public/"): if not relpath.startswith(subpath + "/"):
# print("Skip:", relpath) # print("Skip:", relpath)
continue continue
@ -261,7 +263,7 @@ def regen_all(src_top, dest_top, *, docs=None, db=None):
topLevelHeadline = topLevelHeadline.parent topLevelHeadline = topLevelHeadline.parent
# Save for full-text-search # Save for full-text-search
cur.execute('''INSERT INTO note_search(note_id, title, body, top_level_title, is_done, is_todo, parser_namespace, url) VALUES (?, ?, ?, ?, ?, ?, ?, ?);''', cur.execute('''INSERT INTO note_search(note_id, title, body, top_level_title, is_done, is_todo) VALUES (?, ?, ?, ?, ?, ?);''',
( (
headline.id, headline.id,
headline.title.get_text(), headline.title.get_text(),
@ -269,8 +271,6 @@ def regen_all(src_top, dest_top, *, docs=None, db=None):
topLevelHeadline.title.get_text(), topLevelHeadline.title.get_text(),
headline.is_done, headline.is_done,
headline.is_todo, headline.is_todo,
PARSER_NAMESPACE,
headline.id + '.node.html',
)) ))
# Update graph, replace document ids with headline ids # Update graph, replace document ids with headline ids
@ -350,15 +350,15 @@ def regen_all(src_top, dest_top, *, docs=None, db=None):
dirs_exist_ok=True) dirs_exist_ok=True)
def main(src_top, dest_top): def main(src_top, dest_top, subpath):
notifier = inotify.adapters.InotifyTrees([src_top, STATIC_PATH]) notifier = inotify.adapters.InotifyTrees([src_top, STATIC_PATH])
## Initial load ## Initial load
t0 = time.time() t0 = time.time()
os.makedirs(dest_top, exist_ok=True) os.makedirs(dest_top, exist_ok=True)
db = create_db(os.path.join(dest_top, '..', 'db.sqlite3')) db = create_db(os.path.join(dest_top, 'db.sqlite3'))
docs = regen_all(src_top, dest_top, db=db) docs = regen_all(src_top, dest_top, subpath=subpath, db=db)
if not WATCH: if not WATCH:
logging.info("Build completed in {:.2f}s".format(time.time() - t0)) logging.info("Build completed in {:.2f}s".format(time.time() - t0))
@ -376,7 +376,7 @@ def main(src_top, dest_top):
print("CHANGED: {}".format(filepath)) print("CHANGED: {}".format(filepath))
t0 = time.time() t0 = time.time()
try: try:
docs = regen_all(src_top, dest_top, docs=docs, db=db) docs = regen_all(src_top, dest_top, subpath=subpath, docs=docs, db=db)
except: except:
logging.error(traceback.format_exc()) logging.error(traceback.format_exc())
logging.error("Loading new templates failed 😿") logging.error("Loading new templates failed 😿")
@ -826,9 +826,13 @@ def save_changes(doc):
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) != 3: if len(sys.argv) not in (3, 4):
print("Usage: {} SOURCE_TOP DEST_TOP".format(sys.argv[0])) print("Usage: {} SOURCE_TOP DEST_TOP <SUBPATH>".format(sys.argv[0]))
exit(0) exit(0)
logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s") logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
exit(main(sys.argv[1], sys.argv[2])) subpath = DEFAULT_SUBPATH
if len(sys.argv) == 4:
subpath = sys.argv[3]
exit(main(sys.argv[1], sys.argv[2], subpath=subpath))

View File

@ -1,3 +1,5 @@
/* Dark mode. */
@media (prefers-color-scheme: dark) {
pre { line-height: 125%; } pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
@ -80,3 +82,4 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
.vi { color: #f8f8f2 } /* Name.Variable.Instance */ .vi { color: #f8f8f2 } /* Name.Variable.Instance */
.vm { color: #f8f8f2 } /* Name.Variable.Magic */ .vm { color: #f8f8f2 } /* Name.Variable.Magic */
.il { color: #ae81ff } /* Literal.Number.Integer.Long */ .il { color: #ae81ff } /* Literal.Number.Integer.Long */
}

View File

@ -6,11 +6,13 @@
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<style> <style>
body { body {
background-color: white;
font-family: sans-serif; font-family: sans-serif;
margin: 0 auto; margin: 0 auto;
width: fit-content; width: fit-content;
max-width: 100ex; max-width: 100ex;
padding: 0 1ex; padding: 0 1ex;
color: black;
} }
.header h1 { .header h1 {
text-align: center; text-align: center;
@ -45,7 +47,7 @@
border-right: 1px solid #000; border-right: 1px solid #000;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html { body {
background-color: #1d1f21; background-color: #1d1f21;
color: #fafafe; color: #fafafe;
} }
@ -72,6 +74,12 @@
</div> </div>
<div class="links"> <div class="links">
<a href="/notes">
<section>
<h2>Notes</h2>
<p>Some publicly-visible notes from a sort of knowledge graph that I use as information dump.</p>
</section>
</a>
<section> <section>
<h2><a href="/blog">Blog</a></h2> <h2><a href="/blog">Blog</a></h2>
<p> <p>
@ -100,12 +108,24 @@
</ul> </ul>
</p> </p>
</section> </section>
<a href="/notes">
<section> <section>
<h2>Notes</h2> <h2>Talks / Slides</h2>
<p>Some publicly-visible notes from a sort of knowledge graph that I use as information dump.</p> <p>
<ul>
<li>
Malleable Software
(<a href="/slides/hackliza2024/software-maleable/software-maleable.odp">galician, </a>
for <a href="https://hackliza.gal">Hackliza</a>
<a href="/slides/hackliza2024/software-maleable/software-maleable.pdf">[PDF]</a>
<a href="/slides/hackliza2024/software-maleable/software-maleable.odp">[ODP]</a>)
(<a href="/slides/eslibre2024/software-maleable.odp">spanish,</a>
for <a href="https://eslib.re/2024/">esLibre 2024</a>
<a href="/slides/eslibre2024/software-maleable.pdf">[PDF]</a>
<a href="/slides/eslibre2024/software-maleable.odp">[ODP]</a>).
</li>
</ul>
</p>
</section> </section>
</a>
<!-- section> <!-- section>
<h2>Projects</h2> <h2>Projects</h2>
<p> <p>
@ -116,7 +136,7 @@
<section id="social"> <section id="social">
<h2>Find me</h2> <h2>Find me</h2>
<p> <p>
<a href="https://social.codigoparallevar.com/@kenkeiras">Mastodon</a> <a href="https://social.codigoparallevar.com/@kenkeiras">ActivityPub</a>
<a href="https://github.com/kenkeiras">GitHub</a> <a href="https://github.com/kenkeiras">GitHub</a>
<a href="https://gitlab.com/kenkeiras">GitLab</a> <a href="https://gitlab.com/kenkeiras">GitLab</a>
<a href="https://programaker.com/users/kenkeiras">PrograMaker</a> <a href="https://programaker.com/users/kenkeiras">PrograMaker</a>

View File

@ -10,6 +10,8 @@ body {
max-width: 80ex; max-width: 80ex;
margin: 0 auto; margin: 0 auto;
padding: 0.5ex 1ex; padding: 0.5ex 1ex;
background-color: white;
color: black;
} }
body.blog { body.blog {
@ -332,6 +334,11 @@ h1.title .state.todo-True {
h1.title .state.todo-False { h1.title .state.todo-False {
background-color: rgba(0,255,0,0.25); background-color: rgba(0,255,0,0.25);
} }
h1.title .state.todo-True.state-SOMETIME {
background-color: #ddd;
color: black;
}
h1.title .tags { h1.title .tags {
float: right; float: right;
@ -368,6 +375,7 @@ a.internal::after {
} }
a.external::after { a.external::after {
content: ' ↗'; content: ' ↗';
vertical-align: top;
} }
/* Markup */ /* Markup */
@ -580,7 +588,7 @@ tr.__table-separator {
/* Dark mode. */ /* Dark mode. */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html { html, body {
background-color: #1d1f21; background-color: #1d1f21;
color: #fafafe; color: #fafafe;
} }