diff options
author | luxagraf <sng@luxagraf.net> | 2019-01-13 11:51:02 -0600 |
---|---|---|
committer | luxagraf <sng@luxagraf.net> | 2019-01-13 11:51:02 -0600 |
commit | c4da428fc9ec439389b7473ba5638d9f82085475 (patch) | |
tree | 2c135804e201b3008fe56db25d993881a49da686 | |
parent | 120021d565eefa0318c487f0ff5707c7b9893b43 (diff) |
updated income and resume apps
-rw-r--r-- | app/income/models.py | 13 | ||||
-rw-r--r-- | app/income/parser.py | 42 | ||||
-rw-r--r-- | app/income/views.py | 14 | ||||
-rw-r--r-- | app/resume/admin.py | 18 | ||||
-rw-r--r-- | app/resume/migrations/0004_job_resume.py | 37 | ||||
-rw-r--r-- | app/resume/migrations/0005_job_slug.py | 18 | ||||
-rw-r--r-- | app/resume/migrations/0006_auto_20190112_1257.py | 22 | ||||
-rw-r--r-- | app/resume/migrations/0007_auto_20190113_1128.py | 18 | ||||
-rw-r--r-- | app/resume/migrations/0008_auto_20190113_1139.py | 24 | ||||
-rw-r--r-- | app/resume/migrations/0009_job_body_html.py | 18 | ||||
-rw-r--r-- | app/resume/migrations/0010_auto_20190113_1147.py | 25 | ||||
-rw-r--r-- | app/resume/models.py | 37 | ||||
-rw-r--r-- | app/resume/urls.py | 29 | ||||
-rw-r--r-- | app/resume/views.py | 10 | ||||
-rw-r--r-- | app/utils/util.py | 11 | ||||
-rw-r--r-- | design/sass/pdf_gen.scss | 140 | ||||
-rw-r--r-- | design/templates/archives/notes.html | 6 | ||||
-rw-r--r-- | design/templates/details/invoice.html | 97 | ||||
-rw-r--r-- | design/templates/details/pubs.html | 23 | ||||
-rw-r--r-- | design/templates/details/resume.html | 163 |
20 files changed, 700 insertions, 65 deletions
diff --git a/app/income/models.py b/app/income/models.py index 688d1d7..e5a351b 100644 --- a/app/income/models.py +++ b/app/income/models.py @@ -69,6 +69,9 @@ class InvoiceItem(models.Model): time_end = models.DateTimeField(null=True, blank=True) work_done = models.TextField(null=True, blank=True) + class Meta: + ordering = ('time_start',) + def __str__(self): return str(self.time_start) @@ -89,6 +92,12 @@ class InvoiceItem(models.Model): half_period_seconds = period_seconds / 2 remainder = td.total_seconds() % period_seconds if remainder >= half_period_seconds: - return timedelta(seconds=td.total_seconds() + (period_seconds - remainder)) + tdr = timedelta(seconds=td.total_seconds() + (period_seconds - remainder)) + hours, remainder = divmod(tdr.total_seconds(), 3600) + r = remainder/3600 + return float(hours)+r else: - return timedelta(seconds=td.total_seconds() - remainder) + tdr = timedelta(seconds=td.total_seconds() - remainder) + hours, remainder = divmod(tdr.total_seconds(), 3600) + r = remainder/3600 + return float(hours)+r diff --git a/app/income/parser.py b/app/income/parser.py index 9524902..b19d039 100644 --- a/app/income/parser.py +++ b/app/income/parser.py @@ -1,19 +1,23 @@ -with open('timesheet.csv', newline='') as csvfile: - reader = csv.reader(csvfile, delimiter=';') - counter = 0 - f = "%Y-%m-%d %H:%M:%S" - for row in reader: - if counter > 0: - timer = row[0]+' '+row[1] - timerer = row[0]+' '+row[2] - time_start = datetime.datetime.strptime(timer, f) - time_end = datetime.datetime.strptime(timerer, f) - print(row[4]) - print(timerer, time_end) - InvoiceItem.objects.get_or_create( - time_start=time_start, - time_end=time_end, - work_done=row[4] - ) - counter = counter +1 -f = "%Y-%m-%d %H:%M:%S" +import csv +import datetime +from .models import InvoiceItem + + +def read_timesheet(): + with open('timesheet.csv', newline='') as csvfile: + reader = csv.reader(csvfile, delimiter=';') + counter = 0 + f = "%Y-%m-%d %H:%M:%S" + for row in reader: + if counter > 0: + print(row[4]) + timer = row[0]+' '+row[1] + timerer = row[0]+' '+row[2] + time_start = datetime.datetime.strptime(timer, f) + time_end = datetime.datetime.strptime(timerer, f) + InvoiceItem.objects.get_or_create( + time_start=time_start, + time_end=time_end, + work_done=row[4] + ) + counter = counter + 1 diff --git a/app/income/views.py b/app/income/views.py index 2c3e34a..fc22c0d 100644 --- a/app/income/views.py +++ b/app/income/views.py @@ -20,8 +20,7 @@ class MonthlyInvoiceView(DetailView): total_time = [] for item in context['object_list']: total_time.append(item.rounded_total) - duration = (sum(total_time, datetime.timedelta())) - hours = duration.total_seconds() // 3600 + hours = (sum(total_time)) context['total_hours'] = hours context['total_billed'] = int(hours * 100) context['invoice_number'] = self.object.id+21 @@ -37,10 +36,17 @@ class DownloadMonthlyInvoiceView(MonthlyInvoiceView): logger = logging.getLogger('weasyprint') logger.addHandler(logging.FileHandler('weasyprint.log')) self.object = self.get_object() # assign the object to the view - c = {'object': self.object} + context = self.get_context_data() + c = { + 'object': self.object, + 'object_list': context['object_list'], + 'total_hours': context['total_hours'], + 'total_billed': context['total_billed'], + 'invoice_number': self.object.id+23 + } t = render_to_string('details/invoice.html', c).encode('utf-8') html = HTML(string=t, base_url=self.request.build_absolute_uri()) - pdf = html.write_pdf(stylesheets=[CSS(settings.MEDIA_ROOT + 'site/media/pdf_gen.css')], presentational_hints=True) + pdf = html.write_pdf(stylesheets=[CSS(settings.MEDIA_ROOT + '/pdf_gen.css')], presentational_hints=True) response = HttpResponse(pdf, content_type='application/pdf') response['Content-Disposition'] = 'inline; filename="invoice.pdf"' return response diff --git a/app/resume/admin.py b/app/resume/admin.py index 93b186e..0a7594d 100644 --- a/app/resume/admin.py +++ b/app/resume/admin.py @@ -1,15 +1,23 @@ from django.contrib import admin -from .models import Publisher, PubItem +from .models import Publisher, PubItem, Job, Resume -class PublisherAdmin(admin.ModelAdmin): +@admin.register(Job) +class JobAdmin(admin.ModelAdmin): + pass + + +@admin.register(Resume) +class ResumeAdmin(admin.ModelAdmin): pass +@admin.register(Publisher) +class PublisherAdmin(admin.ModelAdmin): + pass + +@admin.register(PubItem) class PubItemAdmin(admin.ModelAdmin): list_display = ('title', 'pub_date', 'publisher', 'admin_link') pass - -admin.site.register(Publisher, PublisherAdmin) -admin.site.register(PubItem, PubItemAdmin) diff --git a/app/resume/migrations/0004_job_resume.py b/app/resume/migrations/0004_job_resume.py new file mode 100644 index 0000000..e056fec --- /dev/null +++ b/app/resume/migrations/0004_job_resume.py @@ -0,0 +1,37 @@ +# Generated by Django 2.1.1 on 2019-01-12 12:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0003_auto_20151211_1925'), + ] + + operations = [ + migrations.CreateModel( + name='Job', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('employer', models.CharField(max_length=200)), + ('date_start', models.DateField(verbose_name='Date Start')), + ('date_end', models.DateField(blank=True, null=True, verbose_name='Date End')), + ('body_markdown', models.TextField(blank=True, null=True)), + ], + options={ + 'ordering': ('-date_end',), + }, + ), + migrations.CreateModel( + name='Resume', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200)), + ('profile', models.TextField()), + ('skills', models.TextField()), + ('experience', models.ManyToManyField(to='resume.Job')), + ], + ), + ] diff --git a/app/resume/migrations/0005_job_slug.py b/app/resume/migrations/0005_job_slug.py new file mode 100644 index 0000000..d18baeb --- /dev/null +++ b/app/resume/migrations/0005_job_slug.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.1 on 2019-01-12 12:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0004_job_resume'), + ] + + operations = [ + migrations.AddField( + model_name='job', + name='slug', + field=models.CharField(blank=True, max_length=50), + ), + ] diff --git a/app/resume/migrations/0006_auto_20190112_1257.py b/app/resume/migrations/0006_auto_20190112_1257.py new file mode 100644 index 0000000..9ee8f1b --- /dev/null +++ b/app/resume/migrations/0006_auto_20190112_1257.py @@ -0,0 +1,22 @@ +# Generated by Django 2.1.1 on 2019-01-12 12:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0005_job_slug'), + ] + + operations = [ + migrations.RemoveField( + model_name='job', + name='slug', + ), + migrations.AddField( + model_name='resume', + name='slug', + field=models.CharField(blank=True, max_length=50), + ), + ] diff --git a/app/resume/migrations/0007_auto_20190113_1128.py b/app/resume/migrations/0007_auto_20190113_1128.py new file mode 100644 index 0000000..a635258 --- /dev/null +++ b/app/resume/migrations/0007_auto_20190113_1128.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.1 on 2019-01-13 11:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0006_auto_20190112_1257'), + ] + + operations = [ + migrations.AlterField( + model_name='job', + name='employer', + field=models.CharField(max_length=200, null=True), + ), + ] diff --git a/app/resume/migrations/0008_auto_20190113_1139.py b/app/resume/migrations/0008_auto_20190113_1139.py new file mode 100644 index 0000000..29d975d --- /dev/null +++ b/app/resume/migrations/0008_auto_20190113_1139.py @@ -0,0 +1,24 @@ +# Generated by Django 2.1.1 on 2019-01-13 11:39 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0007_auto_20190113_1128'), + ] + + operations = [ + migrations.RenameField( + model_name='resume', + old_name='experience', + new_name='jobs', + ), + migrations.AlterField( + model_name='job', + name='employer', + field=models.CharField(blank=True, default='', max_length=200), + preserve_default=False, + ), + ] diff --git a/app/resume/migrations/0009_job_body_html.py b/app/resume/migrations/0009_job_body_html.py new file mode 100644 index 0000000..fdeea15 --- /dev/null +++ b/app/resume/migrations/0009_job_body_html.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.1 on 2019-01-13 11:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0008_auto_20190113_1139'), + ] + + operations = [ + migrations.AddField( + model_name='job', + name='body_html', + field=models.TextField(blank=True, null=True), + ), + ] diff --git a/app/resume/migrations/0010_auto_20190113_1147.py b/app/resume/migrations/0010_auto_20190113_1147.py new file mode 100644 index 0000000..879bd55 --- /dev/null +++ b/app/resume/migrations/0010_auto_20190113_1147.py @@ -0,0 +1,25 @@ +# Generated by Django 2.1.1 on 2019-01-13 11:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('resume', '0009_job_body_html'), + ] + + operations = [ + migrations.AlterField( + model_name='job', + name='body_html', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + migrations.AlterField( + model_name='job', + name='body_markdown', + field=models.TextField(blank=True, default=''), + preserve_default=False, + ), + ] diff --git a/app/resume/models.py b/app/resume/models.py index 68f9a7e..390a277 100644 --- a/app/resume/models.py +++ b/app/resume/models.py @@ -1,6 +1,7 @@ from django.db import models from django.utils.encoding import force_text from django.urls import reverse +from django.template.defaultfilters import slugify from utils.util import markdown_to_html @@ -53,3 +54,39 @@ class PubItem(models.Model): if self.body_markdown: self.body_html = markdown_to_html(self.body_markdown) super(PubItem, self).save() + + +class Job(models.Model): + title = models.CharField(max_length=200) + employer = models.CharField(max_length=200, blank=True) + date_start = models.DateField('Date Start') + date_end = models.DateField('Date End', null=True, blank=True) + body_markdown = models.TextField(blank=True) + body_html = models.TextField(blank=True) + + class Meta: + ordering = ('-date_end',) + + def __str__(self): + return '{} - {}'.format(self.title, self.employer) # py3.1+ only + + def save(self, *args, **kwargs): + if self.body_markdown: + self.body_html = markdown_to_html(self.body_markdown) + super(Job, self).save() + + +class Resume(models.Model): + title = models.CharField(max_length=200) + slug = models.CharField(max_length=50, blank=True) + profile = models.TextField() + skills = models.TextField() + jobs = models.ManyToManyField(Job) + + def __str__(self): + return self.title + + def save(self, *args, **kwargs): + if self._state.adding and not self.slug: + self.slug = slugify(self.title) + super(Resume, self).save() diff --git a/app/resume/urls.py b/app/resume/urls.py index 0d8b40a..47e07ad 100644 --- a/app/resume/urls.py +++ b/app/resume/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import path, re_path from django.views.generic.base import RedirectView from . import views @@ -6,34 +6,39 @@ from . import views app_name = "resume" urlpatterns = [ - url( - r'pubs/(?P<page>\d+)/$', + path( + r'<str:slug>', + views.ResumeView.as_view(), + name='resume', + ), + path( + r'pubs/<str:page>/', views.PublisherListView.as_view(), name='list', ), - url( - r'pubs/(?P<publisher>[-\w]+)/(?P<page>\d+)/$', + path( + r'pubs/<str:publisher>/<str:page>/', views.ByPublisherListView.as_view(), name='list_by_publisher', ), - url( - r'pubs/(?P<publisher>[-\w]+)/(?P<slug>[-\w]+)$', + path( + r'pubs/<str:publisher>/<str:slug>', views.PubItemDetailView.as_view(), name='detail', ), # redirect /slug/ to /slug/1/ for live server - url( + path( r'pubs/(?P<publisher>[-\w]+)/$', RedirectView.as_view(url="/resume/pubs/%(publisher)s/1/", permanent=False), name="live_publisher_redirect" ), - url( - r'pubs/$', + path( + r'pubs/', RedirectView.as_view(url="/resume/pubs/1/", permanent=False), name="live_redirect" ), - url( - r'^(?P<path>[-\w]+)(?:/(?P<slug>[-\w]+))$', + path( + r'<str:path>/<str:slug>', views.PageView.as_view(), name="pages" ), diff --git a/app/resume/views.py b/app/resume/views.py index 15acf14..9cdd8e7 100644 --- a/app/resume/views.py +++ b/app/resume/views.py @@ -2,7 +2,7 @@ from django.views.generic.detail import DetailView from django.views.generic.base import TemplateView from utils.views import PaginatedListView -from .models import PubItem, Publisher +from .models import PubItem, Publisher, Resume from pages.models import Page @@ -32,9 +32,10 @@ class ByPublisherListView(PaginatedListView): context['publisher'] = Publisher.objects.get(slug=self.kwargs['publisher']) return context + class PubItemDetailView(DetailView): model = PubItem - template_name = "details/resume.html" + template_name = "details/pubs.html" slug_field = "slug" @@ -51,3 +52,8 @@ class PageView(DetailView): def get_template_names(self): return ["details/%s.html" % self.object.slug, 'details/page.html'] + + +class ResumeView(DetailView): + model = Resume + template_name = "details/resume.html" diff --git a/app/utils/util.py b/app/utils/util.py index 6678fc9..714403b 100644 --- a/app/utils/util.py +++ b/app/utils/util.py @@ -110,3 +110,14 @@ def parse_video(s): if soup.find('video'): return True return False + +def parse_reg_bio_page(): + content = requests.get("https://www.theregister.co.uk/Author/Scott-Gilbertson/") + soup = BeautifulSoup(content, 'html.parser') + try: + image = soup.find_all('img')[0]['id'] + img_pk = image.split('image-')[1] + return apps.get_model('photos', 'LuxImage').objects.get(pk=img_pk) + except IndexError: + return None + diff --git a/design/sass/pdf_gen.scss b/design/sass/pdf_gen.scss new file mode 100644 index 0000000..b5072cd --- /dev/null +++ b/design/sass/pdf_gen.scss @@ -0,0 +1,140 @@ +@import "_fonts.scss"; +@import "_mixins.scss"; + +body { + @include fancy_sans; +} +.subhead { + text-align: right; + width: 4cm; + float: right; + @extend %clearfix; + > * { + margin: 0; + font-weight: 400; + } +} +header, .row { + @extend %clearfix; + margin-top: 1cm; +} +.print-box { + width: 49%; + float: left; + > * { + padding: .125cm; + margin: 0; + } + h5, h4 { + @include smcaps; + font-size: 9pt; + line-height: .5; + } + h4 { + margin-top: -10pt; + font-size: 16pt; + line-height: 1.5; + } +} +#bill-from, #bill { + border: none; + width: 47%; + float: left; +} +#bill { + float: right; +} +#bill-to { + width: 47%; + float: right; +} +table { + font-family: "Open Sans", sans-serif; + line-height: 1; + border: 1px solid #ccc; + border-collapse: collapse; + margin: 1cm 0 0 0; + padding: 0; + width: 625px; +} +table caption { + text-align: left; + font-size: 10pt; + text-transform: uppercase; + font-weight: 600; + margin: .5em 0 .75em; + &:after { + content: ":"; + } +} +table tr { + border: 1px solid #ddd; + padding: .35em; +} +table tr.odd { background: #f6f4f4cc;} +thead {display: table-header-group; } +table th, +table td { + padding: .625em .625em .625em 1em; + text-align: left; + border-right: 1px solid #ddd; +} +table td { + white-space: -o-pre-wrap; + word-wrap: break-word; + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -pre-wrap; + font-size: 8pt; +} +table th { + font-size: 7pt; + letter-spacing: .1em; + text-transform: uppercase; + background: #f6f4f4; +} + +table .blank { + white-space: normal; + td { + padding: 1rem; + white-space: normal; + &:last-of-type { + text-align: left; + min-width: 1.2cm; + } + } +} +table .right { + text-align: right; +} +table th a { + text-decoration: none; + position: relative; + span { + position: absolute; + top: -2px; + } +} +.smfield { min-width: 50pt;} +table .total { font-size: 9pt !important;} +.thanks { + margin-top: 40pt; + font-family: times, times new roman; + font-style: italic; + font-weight: 300; + text-align: center; + color: #333; +} + +@page { + @bottom-right{ + @include fancy_sans; + @include smcaps; + content: "Page " counter(page) " of " counter(pages); + font-size: 6pt; + color: #666; + width: 2cm; + } +} + diff --git a/design/templates/archives/notes.html b/design/templates/archives/notes.html index 998546f..8dc168e 100644 --- a/design/templates/archives/notes.html +++ b/design/templates/archives/notes.html @@ -1,6 +1,7 @@ {% extends 'base.html' %} {% load typogrify_tags %} {% load html5_datetime %} +{% load pagination_tags %} {% block pagetitle %} Field Notes | luxagraf {% endblock %} {% block metadescription %} Rough notes and sketches from the field {% endblock %} {%block bodyid%}class="notes" id="notes-archive"{%endblock%} @@ -13,7 +14,7 @@ <main role="main"> <h1>Field Notes</h1> <h4 class="subhead divide-after">Quick notes and images from the road</h4> - {% for object in object_list %} + {% autopaginate object_list 2 %}{% for object in object_list %} <article class="h-entry"> <h2 class="p-name note--title hide">{{object.title|safe|amp|smartypants}}</h2> <h5 class="note--date-hed"><a class="u-url" href="{{object.get_absolute_url}}" rel="bookmark"><time class="dt-published" datetime="{{object.pub_date|html5_datetime}}">{{object.pub_date|date:"F j, Y"}}</time></a></h5> @@ -56,6 +57,9 @@ </article> {% endfor %} </main> + <nav class="pagination"> + {% paginate %} + </nav> {% endblock %} diff --git a/design/templates/details/invoice.html b/design/templates/details/invoice.html new file mode 100644 index 0000000..1a812c8 --- /dev/null +++ b/design/templates/details/invoice.html @@ -0,0 +1,97 @@ +{% load typogrify_tags %} + +<!DOCTYPE html> +<html dir="ltr" lang="en-US"> +<head> + <title>Invoice for {{object.title}}</title> + <meta charset="utf-8"> + <meta http-equiv="x-ua-compatible" content="ie=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta name="description" + content=""> +<style> + @page { + @bottom-left { + content: ""; + } + } +</style> +</head> + {% load static %} +<body id="quote"> + <div class="row"> + <div class="print-box" id="bill-from"> + <h5>Bill From:</h5> + <p>Scott Gilbertson <br /> + 1806 Dover Dr. <br /> + Newport Beach, CA 92660<br /> + 706-438-4297</p> + </div> + <div class="print-box" id="bill"> + <h4>Invoice {{invoice_number}}</h4> + <h5>Invoice For: {{object.title}}</h5> + <h5>Amount Due: ${{total_billed}}</h5> + <h5>Sent on: {% now "M j, Y"%}</h5> + </div> + </div> + <div class="row"> + <div class="print-box" id="bill-to"> + <h5>Bill To:</h5> + <p>Enterprise Data Resources, Inc.<br /> + 1089 Culpepper Drive <br /> + Conyers, GA 30094 <br /> + 707-973-2862</p> + </div> + </div> + </div> +<table class="quote-table" id="items_list"> +<thead> + <caption>Items</caption> +<tr> +<th scope="col" class="sortable column-status"> + <div class="text">Date</div> +</th> +<th scope="col" class="sortable column-created_at sorted descending"> + <div class="text">Time</div> +</th> +<th scope="col" class="sortable column-repair_state"> + <div class="text">Hours</div> +</th> +<th scope="col" class="sortable column-order_id"> + <div class="text">Tasks</div> +</th> +</tr> +</thead> +<tbody> + {% for obj in object_list %} + <tr class="row{{forloop.counter}} {% cycle 'odd' 'even' %}"> + <td class="smfield" data-label="">{{obj.time_start|date:"m/d/y"}}</td> + <td class="smfield" data-label="Serial" >{{obj.time_start|date:"g:i"}} - {{obj.time_end|date:"g:i"}}</td> + <td class="smfield" data-label="Serial" >{{obj.rounded_total}}</td> + <td class="field" data-label="Issue" >{{obj.work_done|capfirst}}</td> + </tr> + {%endfor%} + <tr class="row gap"> + </tr> + <tr class="row2"> + <td class="field-payment_status"></td> + <td class="field-pub_date nowrap"></td> + <th class="field-title">Total Hours:</th> + <td class="field-status">{{total_hours}}</td> + </tr> + <tr class="row2"> + <td class="field-payment_status"></td> + <td class="field-pub_date nowrap"></td> + <th class="field-title">Rate:</th> + <td class="field-status">$100/hr</td> + </tr> + <tr class="row2"> + <td class="field-payment_status"></td> + <td class="field-pub_date nowrap"></td> + <th class="field-title total">Total for Invoice:</th> + <td class="field-status total"><b>${{total_billed}}</b></td> + </tr> +</tbody> +</table> +<p class="thanks">Thank you for your prompt payment</p> +</body> diff --git a/design/templates/details/pubs.html b/design/templates/details/pubs.html new file mode 100644 index 0000000..ff16bbe --- /dev/null +++ b/design/templates/details/pubs.html @@ -0,0 +1,23 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} + +{% block pagetitle %}{% endblock %} +{% block metadescription %}{% endblock %} + +{%block htmlclass%}class="detail{%endblock%} + +{% block primary %}<ul class="bl" id="breadcrumbs" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> + <li><a href="/" title="luxagraf homepage" itemprop="url"><span itemprop="title">Home</span></a> → </li> + <li><a href="/resume">Resume</a>{% if object.title != "Resume" %} → {%endif%}</li> + {% if object.title != "Resume" %}<li><a href="/resume/pubs/">Publications</a></li>{%endif%} + </ul> + <main> + <article> + {% if object.title != "Resume" %}<h1 class="post-header">{{object.title|safe|smartypants|widont}}</h1>{% endif %} + {% if object.publisher %}<p><i>This article was published in {{object.publisher}}, you can view <a href="{{object.url}}">the original</a> there, complete with graphics, comments and other fun stuff.</i></p>{% endif %} + <div class="post-article" style="margin-top: 3em"> + {{object.body_html|safe|smartypants|widont}} + </div> + </article> + </main> + {%endblock%} diff --git a/design/templates/details/resume.html b/design/templates/details/resume.html index ff16bbe..611765c 100644 --- a/design/templates/details/resume.html +++ b/design/templates/details/resume.html @@ -1,23 +1,146 @@ {% extends 'base.html' %} {% load typogrify_tags %} +{% block pagetitle %}Scott Gilbertson - Curriculum Vitæ{%endblock%} +{% block extrahead%} + <meta name="twitter:card" content="summary"> + <meta name="twitter:title" content="Curriculum Vitæ"> + <meta name="twitter:description" content="luxagraf.net is the personal web site of Scott gilbertson."> + <meta name="twitter:site:id" content="9469062"> + <meta name="twitter:creator:id" content="9469062"> + <meta property="og:type" content="article"/> + <meta property="og:title" content="Scott Gilbertson - Curriculum Vitæ"/> + <meta property="og:url" content="http://luxagraf.net/resume/cv"/> + <meta property="og:description" content="luxagraf.net is the personal web site of Scott gilbertson."> + <meta property="article:author" content="Scott Gilbertson"/> + <meta property="og:site_name" content="luxagraf.net"/> + <meta property="og:locale" content="en_US"/> +<style> +</style>{%endblock%} +{%block bodyid%}class="resume"{%endblock%} +{%block htmlclass %}class="detail"{%endblock%} +{% block primary %} +<main role="main" id="content"> +<article class="h-resume"> + <div class="h-card head"> + <header> + <h1 class="p-name"> + <span class="p-given-name">Scott</span> + <span class="p-additional-name hide">Nathan</span> + <span class="p-family-name">Gilbertson</span> + </h1> + <h2>Writer, Photographer, Web Developer</h2> + </header> + <ul class="contact"> + <li> + <h6>Phone</h6> + <span><a class="u-tel" href="tel:706-438-4297">706-438-4297</a></span> + </li> + <li> + <h6>Email</h6> + <a class="u-email" href="mailto:sng@luxagraf.net">sng@luxagraf.net</a> + </li> + <li> + <h6>Web</h6> + <span><a class="u-url" href="https://luxagraf.net/" rel="me">https://luxagraf.net/</a></span> + </li> + <li> + <h6>LinkedIn</h6> + <span><a class="u-url" href="https://www.linkedin.com/in/luxagraf" rel="me">luxagraf</a></span> + </li> + </ul> + </div> + <div class="profile"> + <h3>Profile</h3> + <p class="p-summary">I am a writer, producer and web developer based in Athens, GA. Clients include Wired, Webmonkey, Ars Technica, Pioneer and Boost Mobile, among others. I wrote for Wired.com’s Webmonkey.com for 13 years and served as head editor for three. I’ve been developing on the web and writing about web development for nearly two decades. For an up-to-date list of recent articles, please browse <a href="/resume/pubs/">the publications list</a>.</p> + </div> -{% block pagetitle %}{% endblock %} -{% block metadescription %}{% endblock %} - -{%block htmlclass%}class="detail{%endblock%} - -{% block primary %}<ul class="bl" id="breadcrumbs" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> - <li><a href="/" title="luxagraf homepage" itemprop="url"><span itemprop="title">Home</span></a> → </li> - <li><a href="/resume">Resume</a>{% if object.title != "Resume" %} → {%endif%}</li> - {% if object.title != "Resume" %}<li><a href="/resume/pubs/">Publications</a></li>{%endif%} - </ul> - <main> - <article> - {% if object.title != "Resume" %}<h1 class="post-header">{{object.title|safe|smartypants|widont}}</h1>{% endif %} - {% if object.publisher %}<p><i>This article was published in {{object.publisher}}, you can view <a href="{{object.url}}">the original</a> there, complete with graphics, comments and other fun stuff.</i></p>{% endif %} - <div class="post-article" style="margin-top: 3em"> - {{object.body_html|safe|smartypants|widont}} - </div> - </article> - </main> - {%endblock%} + <div id="skills"> + <h3>Skills</h3> + + <h2><a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Writing">Writing</a></h2> + <p>Freelance writer, producer, journalist, editor and hand model at places like Wired, Ars Technica, Budget Travel. I’ve written blogs, features, news items, ad copy, technical documentation, tutorials, how-tos, wikis and probably other things I’ve forgotten about. I also served as editor-in-chief of Webmonkey.com.</p> + + <h2><a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Web_development">Web Development</a></h2> + <p>Expert front-end engineer in <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Web_standards">standards-based web development</a> using <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/HTML"><abbr title="Hypertext Markup Language">HTML</abbr></a>, <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets"><abbr title="Cascading Style Sheets">CSS</abbr></a>, and high performance <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/JavaScript">JavaScript</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Responsive_web_design">responsive design</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>, <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Microformats">microformats</a>, <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/ARIA">ARIA</a> and more. </p> + <p>Experience maintaining large-scale web applications and tools with <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Python_(programming_language)">Python</a> and <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/PHP">PHP</a> in conjunction with databases like <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/PostgreSQL">PostgreSQL</a> (including numerous PostGIS, geographic database projects), <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/MySQL">MySQL</a>, <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Sqlite">Sqlite</a>. Experience administering <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Linux">Linux </a> servers and running web servers like <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Apache_HTTP_Server">Apache</a>, and <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Nginx">Nginx</a>.</p> + <p>Advocate and evangelist for free software and open web standards technologies such as <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/HTML5">HTML5</a>, related APIs, <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS3</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Responsive_web_design">responsive design</a> (including <a href="https://longhandpixels.net/books/responsive-web-design">a 350 page book on the subject</a>) and <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>.</p> + + <h2><a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Graphic_design">Photography/Video/Design</a></h2> + <p>Good design eye specializing in fluid, clean layouts with strong <a class="p-skill" rel="tag" href="http://en.wikipedia.org/wiki/Typography">typographic style</a>. </p> + <p>Photo and video editing using <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Adobe_Photoshop">Photoshop</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/GIMP">GIMP</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Adobe_Photoshop_Lightroom">Lightroom</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Darktable">Darktable</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Final_Cut_Pro">Final Cut Pro</a>, and <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Kdenlive">Kdenlive</a>.</p> + + </div> + + <div class="h-calendar" id="experience"> + <h3>Experience</h3>{% for job in object.jobs.all %} + <div class="p-experience h-event"> + <h2 class="p-name">{{job.title}}</h2> + <ul class="meta"> + <li>(<time class="dt-start" datetime="{{job.date_start}}">{{job.date_start|date:"M Y"}}</time>–{% if job.date_end %}<time class="dt-end" datetime="{{job.date_end}}">{{job.date_end|date:"M Y"}}</time>{%else%}<span class="dt-end">present</span>{%endif%})</li> + </ul> + <p class="e-description">{{job.body_html|safe}}</p> + </div>{% endfor %} + + {%comment%} + <div class="p-experience h-event"> + <h2 class="p-name">Web Developer</h2> + <ul class="meta"> + <li>(<time class="dt-start" datetime="2004-06-01">June 2004</time>–Present) + </li> + </ul> + <p class="e-description">Co-founded a small design company where I serve as front-end web developer. I work closely with my co-founder (lead UI/UX), transforming visual designs into valid, semantic HTML/CSS/JavaScript. We specialize in responsive designs and mobile-friendly content that works across browsers and devices. Clients included Wired, Pioneer Entertainment, Boost Mobile, Co-op Credit Union and others.</p> + </div> + + <div class="p-experience h-event"> + <h2 class="p-name">Founder, LongHandPixels Press</h2> + <ul class="meta"> + <li>(<time class="dt-start" datetime="2013-09-01">September 2013</time>–Present) + </li> + </ul> + <p class="e-description">Founded an ebook publishing company, <a href="http://longhandpixels.net/" class="p-organization-name">LongHandPixels Press</a> and launched my first book, <em><a href="https://longhandpixels.net/books/responsive-web-design">Build a Better Web with Responsive Web Design</a></em>. The book covers responsive design, mobile-first web development, progressive enhancement and how modern tools like Sass, Grunt, Node, the Chrome developer tools and more can speed up workflows. + </p> + </div> + + <div class="p-experience h-event"> + <h2 class="p-name">Writer/Editor Webmonkey.com</h2> + <ul class="meta"> + <li class="h-location h-card"> + <a class="u-url p-name" href="http://webmonkey.com"> + <span class="p-organization-name">Wired.com</span>/ + <span class="p-organization-unit">Webmonkey.com</span></a> + </li> + <li>(<time class="dt-start" datetime="2006-06-01">June 2006</time> + –<time class="dt-end" datetime="2013-04-31">April 2013</time>) + </li> + </ul> + <p class="e-description">I started contributing tutorials to Wired.com’s Webmonkey.com in 1999, became a full time employee in 2006 and served as editor-in-chief from 2010 to 2013. I was in charge of creating resources for web developers, including how-to guides on the latest in web standards, code libraries, server technologies and authoring resources. Wrote roughly 3 million words on various web development tools. I also helped cultivate and manage a global team of freelance contributors.</p> + </div> + + <div class="p-experience h-event"> + <h2 class="p-name">Photography and Video Editing</h2> + <ul class="meta"> + <li class="h-location h-card"><a class="u-url p-name" href="http://barrelmanproductions.com"><span class="p-organization-name">barrelmanproductions.com</span></a></li> + <li>(<time class="dt-start" datetime="2006-06-01">June 2014</time> - Present)</li> + </ul> + <p class="e-description">Co-founded a video editing company, Barrelman Productions, specializing in HD aerial video. Portfolio and highlights reel available at <a href="http://www.barrelmanproductions.com/">http://www.barrelmanproductions.com/</a>. Skills include editing in <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Final_Cut_Pro">Final Cut Pro</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Adobe_Photoshop">Photoshop</a>, <a class="p-skill" rel="tag" href="https://en.wikipedia.org/wiki/Adobe_Photoshop_Lightroom">Lightroom</a> and production of web-optimized video.</p> + </div> + {%endcomment%} + + </div> + <div class="h-calendar" id="education"> + <h3>Education</h3> + + <div class="p-education h-event"> + <h2 class="p-name">Bachelor of Arts, English</h2> + <ul class="meta"> + <li>Undergraduate degree from <a class="p-location h-card" href="http://uga.edu/">The University of <span class="p-locality">Georgia</span>.</a></li> + <li>(<time class="dt-start" title="2001-08-01">2001</time>–<time class="dt-end" title="2003-12-16">2003</time>)</li> + </ul> + </div> + + </div> + +</article> + +</main> +{%endblock%} |