Simple site layout design

This commit is contained in:
2025-06-05 21:52:01 -06:00
parent 63861e1721
commit 94950041f6
62 changed files with 618 additions and 140 deletions

125
assets/bib2yaml.py Normal file
View File

@ -0,0 +1,125 @@
import sys
import re
def remove_comments(text):
return re.sub(r'(?m)^[ \t]*%.*\n?', '', text)
def find_entries(bibtex_content):
entry_regex = re.compile(r'@(\w+)\s*[{(]', re.IGNORECASE)
positions = [m.start() for m in entry_regex.finditer(bibtex_content)]
entries = []
for i, start in enumerate(positions):
end = positions[i+1] if i+1 < len(positions) else len(bibtex_content)
entries.append(bibtex_content[start:end].strip())
return entries
def parse_bibtex_entry(entry):
entry = entry.strip()
if not entry or entry.startswith('%'):
return None
m = re.match(r'@(\w+)\s*[{(]\s*([^,]+),?', entry, re.DOTALL)
if not m:
return None
entry_type, entry_key = m.groups()
entry_type = entry_type.lower()
if entry_type in ('comment', 'preamble'):
return None
if entry_type == 'string':
return None
body = entry[m.end():]
body = body.rstrip('})').strip()
fields = {}
field_regex = re.compile(r'(\w+)\s*=\s*', re.DOTALL)
pos = 0
while pos < len(body):
m = field_regex.match(body, pos)
if not m:
break
field = m.group(1)
pos = m.end()
if body[pos] == '{':
brace_level = 1
val_start = pos + 1
pos += 1
while pos < len(body) and brace_level > 0:
if body[pos] == '{':
brace_level += 1
elif body[pos] == '}':
brace_level -= 1
pos += 1
value = body[val_start:pos-1]
elif body[pos] == '"':
val_start = pos + 1
pos += 1
while pos < len(body) and body[pos] != '"':
if body[pos] == '\\':
pos += 2
else:
pos += 1
value = body[val_start:pos]
pos += 1
else:
val_start = pos
while pos < len(body) and body[pos] not in ',\n':
pos += 1
value = body[val_start:pos].strip()
fields[field] = value.replace('\n', ' ').strip()
while pos < len(body) and body[pos] in ', \n\r\t':
pos += 1
return entry_type, entry_key, fields
def escape_yaml_string(s):
# Escape double quotes and backslashes, wrap in double quotes if needed
if not s:
return '""'
if any(c in s for c in ':\'"{}[],&*#?|-<>=!%@`\\\n'):
s = s.replace('\\', '\\\\').replace('"', '\\"')
return f'"{s}"'
return s
def dict_to_yaml(d, indent=0):
lines = []
for k, v in d.items():
if isinstance(v, list):
lines.append(' ' * indent + f"{k}:")
for item in v:
lines.append(' ' * (indent + 2) + f"- {escape_yaml_string(item)}")
else:
lines.append(' ' * indent + f"{k}: {escape_yaml_string(v)}")
return '\n'.join(lines)
def bibtex_to_yaml(bibtex_content):
bibtex_content = remove_comments(bibtex_content)
entries = find_entries(bibtex_content)
yaml_entries = []
for entry in entries:
parsed = parse_bibtex_entry(entry)
if not parsed:
continue
entry_type, entry_key, fields = parsed
entry_dict = {'key': entry_key}
if "author" in fields:
authors = [a.strip() for a in re.split(r'\s+and\s+', fields["author"])]
entry_dict['author'] = authors
del fields["author"]
entry_dict.update(fields)
yaml_entries.append(entry_dict)
yaml_str = "publications:\n"
for entry in yaml_entries:
yaml_str += " - " + dict_to_yaml(entry, indent=4).lstrip().replace('\n', '\n ') + "\n"
return yaml_str
def main():
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <input.bib>")
sys.exit(1)
bibfile = sys.argv[1]
with open(bibfile, 'r', encoding='utf-8') as f:
bibtex_content = f.read()
yaml_content = bibtex_to_yaml(bibtex_content)
yamlfile = bibfile.rsplit('.', 1)[0] + '.yaml'
with open(yamlfile, 'w', encoding='utf-8') as f:
f.write(yaml_content)
print(f"YAML exported to {yamlfile}")
if __name__ == "__main__":
main()

View File

@ -1,22 +0,0 @@
body {
color: #222;
font-family: sans-serif;
line-height: 1.5;
margin: 1rem;
max-width: 768px;
}
header {
border-bottom: 1px solid #222;
margin-bottom: 1rem;
}
footer {
border-top: 1px solid #222;
margin-top: 1rem;
}
a {
color: #00e;
text-decoration: none;
}

81
assets/sass/_fonts.sass Normal file
View File

@ -0,0 +1,81 @@
$font-path: '/fonts/static/'
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 100
src: local('Source Sans 3 ExtraLight'), local('SourceSans3-ExtraLight'), url('#{$font-path}SourceSans3-ExtraLight.woff2') format('woff2'), url('#{$font-path}SourceSans3-ExtraLight.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 200
src: local('Source Sans 3 ExtraLight'), local('SourceSans3-ExtraLight'), url('#{$font-path}SourceSans3-ExtraLight.woff2') format('woff2'), url('#{$font-path}SourceSans3-ExtraLight.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 300
src: local('Source Sans 3 Light'), local('SourceSans3-Light'), url('#{$font-path}SourceSans3-Light.woff2') format('woff2'), url('#{$font-path}SourceSans3-Light.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 400
src: local('Source Sans 3 Regular'), local('SourceSans3-Regular'), url('#{$font-path}SourceSans3-Regular.woff2') format('woff2'), url('#{$font-path}SourceSans3-Regular.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: italic
font-display: swap
font-weight: 400
src: local('Source Sans 3 Italic'), local('SourceSans3-Italic'), url('#{$font-path}SourceSans3-Italic.woff2') format('woff2'), url('#{$font-path}SourceSans3-Italic.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 500
src: local('Source Sans 3 Medium'), local('SourceSans3-Medium'), url('#{$font-path}SourceSans3-Medium.woff2') format('woff2'), url('#{$font-path}SourceSans3-Medium.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 600
src: local('Source Sans 3 SemiBold'), local('SourceSans3-SemiBold'), url('#{$font-path}SourceSans3-SemiBold.woff2') format('woff2'), url('#{$font-path}SourceSans3-SemiBold.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 700
src: local('Source Sans 3 Bold'), local('SourceSans3-Bold'), url('#{$font-path}SourceSans3-Bold.woff2') format('woff2'), url('#{$font-path}SourceSans3-Bold.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: italic
font-display: swap
font-weight: 700
src: local('Source Sans 3 Bold Italic'), local('SourceSans3-BoldItalic'), url('#{$font-path}SourceSans3-BoldItalic.woff2') format('woff2'), url('#{$font-path}SourceSans3-BoldItalic.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 800
src: local('Source Sans 3 ExtraBold'), local('SourceSans3-ExtraBold'), url('#{$font-path}SourceSans3-ExtraBold.woff2') format('woff2'), url('#{$font-path}SourceSans3-ExtraBold.ttf') format('truetype')
@font-face
font-family: 'Source Sans 3'
font-style: normal
font-display: swap
font-weight: 900
src: local('Source Sans 3 Black'), local('SourceSans3-Black'), url('#{$font-path}SourceSans3-Black.woff2') format('woff2'), url('#{$font-path}SourceSans3-Black.ttf') format('truetype')
*
font-family: 'Source Sans 3', sans-serif

4
assets/sass/main.sass Normal file
View File

@ -0,0 +1,4 @@
@import "fonts"
*
color: white
background: black