Compare commits

..

No commits in common. "63504a5768e1f33a3ef3d0d31b2686001efd0648" and "6def13d2b6cb22ebf75ea6903b1e20f141f72a7e" have entirely different histories.

13 changed files with 284 additions and 222 deletions

BIN
src/web/db.sqlite3 Normal file

Binary file not shown.

View File

@ -1,8 +1,3 @@
from django.contrib import admin from django.contrib import admin
from .models import Game, Purchase, Platform, Session
# Register your models here. # Register your models here.
admin.site.register(Game)
admin.site.register(Purchase)
admin.site.register(Platform)
admin.site.register(Session)

View File

@ -1,98 +0,0 @@
- model: tracker.game
pk: 1
fields:
name: Nioh 2
wikidata: Q67482292
- model: tracker.game
pk: 2
fields:
name: Elden Ring
wikidata: Q64826862
- model: tracker.game
pk: 3
fields:
name: Cyberpunk 2077
wikidata: Q3182559
- model: tracker.purchase
pk: 1
fields:
game: 1
platform: 1
date_purchased: 2021-02-13
date_refunded: null
- model: tracker.purchase
pk: 2
fields:
game: 2
platform: 1
date_purchased: 2022-02-24
date_refunded: null
- model: tracker.purchase
pk: 3
fields:
game: 3
platform: 1
date_purchased: 2020-12-07
date_refunded: null
- model: tracker.platform
pk: 1
fields:
name: Steam
group: PC
- model: tracker.platform
pk: 3
fields:
name: Xbox Gamepass
group: PC
- model: tracker.platform
pk: 4
fields:
name: Epic Games Store
group: PC
- model: tracker.platform
pk: 5
fields:
name: Playstation 5
group: Playstation
- model: tracker.platform
pk: 6
fields:
name: Playstation 4
group: Playstation
- model: tracker.platform
pk: 7
fields:
name: Nintendo Switch
group: Nintendo
- model: tracker.platform
pk: 8
fields:
name: Nintendo 3DS
group: Nintendo
- model: tracker.session
pk: 1
fields:
purchase: 2
timestamp_start: 2022-12-31 14:25:58+00:00
timestamp_end: 2022-12-31 16:25:22+00:00
duration_manual: null
duration_calculated: null
note: ''
- model: tracker.session
pk: 3
fields:
purchase: 3
timestamp_start: 2023-01-01 22:00:23+00:00
timestamp_end: 2023-01-01 23:28:23+00:00
duration_manual: null
duration_calculated: null
note: ''
- model: tracker.session
pk: 4
fields:
purchase: 3
timestamp_start: 2020-01-01 23:29:17+00:00
timestamp_end: 2020-01-01 23:29:17+00:00
duration_manual: '12:00:00'
duration_calculated: null
note: ''

View File

@ -1,7 +1,6 @@
# Generated by Django 4.1.4 on 2023-01-02 18:27 # Generated by Django 4.1.4 on 2022-12-30 22:02
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -12,68 +11,7 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name="Game", name="TrackerModel",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("wikidata", models.CharField(max_length=50)),
],
),
migrations.CreateModel(
name="Platform",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("group", models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name="Purchase",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date_purchased", models.DateField()),
("date_refunded", models.DateField(blank=True, null=True)),
(
"game",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="tracker.game"
),
),
(
"platform",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="tracker.platform",
),
),
],
),
migrations.CreateModel(
name="Session",
fields=[ fields=[
( (
"id", "id",
@ -84,18 +22,10 @@ class Migration(migrations.Migration):
verbose_name="ID", verbose_name="ID",
), ),
), ),
("name", models.CharField(max_length=200)),
("timestamp_start", models.DateTimeField()), ("timestamp_start", models.DateTimeField()),
("timestamp_end", models.DateTimeField()), ("timestamp_end", models.DateTimeField()),
("duration_manual", models.DurationField(blank=True, null=True)), ("note", models.TextField()),
("duration_calculated", models.DurationField(blank=True, null=True)),
("note", models.TextField(blank=True, null=True)),
(
"purchase",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="tracker.purchase",
),
),
], ],
), ),
] ]

View File

@ -0,0 +1,104 @@
# Generated by Django 4.1.4 on 2022-12-31 12:35
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("tracker", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="Game",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("wikidata", models.CharField(max_length=50)),
],
),
migrations.CreateModel(
name="Platform",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=255)),
("group", models.CharField(max_length=255)),
],
),
migrations.CreateModel(
name="Purchase",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date_purchased", models.DateTimeField()),
("date_refunded", models.DateTimeField()),
(
"game",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="tracker.game"
),
),
(
"platform",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="tracker.platform",
),
),
],
),
migrations.CreateModel(
name="Session",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("timestamp_start", models.DateTimeField()),
("timestamp_end", models.DateTimeField()),
("duration_manual", models.DurationField()),
("duration_calculated", models.DurationField()),
("note", models.TextField()),
(
"purchase",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="tracker.purchase",
),
),
],
),
migrations.DeleteModel(
name="TrackerModel",
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.1.4 on 2022-12-31 13:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("tracker", "0002_game_platform_purchase_session_delete_trackermodel"),
]
operations = [
migrations.AlterField(
model_name="purchase",
name="date_purchased",
field=models.DateField(),
),
migrations.AlterField(
model_name="purchase",
name="date_refunded",
field=models.DateField(),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2022-12-31 13:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("tracker", "0003_alter_purchase_date_purchased_and_more"),
]
operations = [
migrations.AlterField(
model_name="purchase",
name="date_refunded",
field=models.DateField(blank=True),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2022-12-31 13:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("tracker", "0004_alter_purchase_date_refunded"),
]
operations = [
migrations.AlterField(
model_name="purchase",
name="date_refunded",
field=models.DateField(blank=True, null=True),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 4.1.4 on 2022-12-31 13:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("tracker", "0005_alter_purchase_date_refunded"),
]
operations = [
migrations.AlterField(
model_name="session",
name="duration_calculated",
field=models.DurationField(blank=True, null=True),
),
migrations.AlterField(
model_name="session",
name="duration_manual",
field=models.DurationField(blank=True, null=True),
),
migrations.AlterField(
model_name="session",
name="note",
field=models.TextField(blank=True, null=True),
),
]

View File

@ -1,5 +1,4 @@
from django.db import models from django.db import models
from datetime import timedelta
class Game(models.Model): class Game(models.Model):
@ -32,20 +31,12 @@ class Session(models.Model):
purchase = models.ForeignKey("Purchase", on_delete=models.CASCADE) purchase = models.ForeignKey("Purchase", on_delete=models.CASCADE)
timestamp_start = models.DateTimeField() timestamp_start = models.DateTimeField()
timestamp_end = models.DateTimeField() timestamp_end = models.DateTimeField()
duration_manual = models.DurationField(blank=True, null=True, default=timedelta(0)) duration_manual = models.DurationField(blank=True, null=True)
duration_calculated = models.DurationField(blank=True, null=True) duration_calculated = models.DurationField(blank=True, null=True)
note = models.TextField(blank=True, null=True) note = models.TextField(blank=True, null=True)
def __str__(self): def __str__(self):
mark = ", manual" if self.duration_manual != None else "" return self.purchase
return f"{str(self.purchase)} {str(self.timestamp_start.date())} ({self.total_duration()}{mark})"
def calculated_duration(self): def calculated_duration(self):
return self.timestamp_end - self.timestamp_start return self.timestamp_end - self.timestamp_start
def total_duration(self):
return (
self.calculated_duration()
if self.duration_manual == None
else self.duration_manual + self.calculated_duration()
)

View File

@ -726,6 +726,10 @@ select {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
.mr-3 {
margin-right: 0.75rem;
}
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@ -742,6 +746,10 @@ select {
display: grid; display: grid;
} }
.h-6 {
height: 1.5rem;
}
.w-full { .w-full {
width: 100%; width: 100%;
} }
@ -790,20 +798,38 @@ select {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
.rounded-lg {
border-radius: 0.5rem;
}
.rounded-xl { .rounded-xl {
border-radius: 0.75rem; border-radius: 0.75rem;
} }
.border {
border-width: 1px;
}
.border-gray-200 { .border-gray-200 {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(229 231 235 / var(--tw-border-opacity)); border-color: rgb(229 231 235 / var(--tw-border-opacity));
} }
.border-gray-100 {
--tw-border-opacity: 1;
border-color: rgb(243 244 246 / var(--tw-border-opacity));
}
.bg-white { .bg-white {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity)); background-color: rgb(255 255 255 / var(--tw-bg-opacity));
} }
.bg-gray-50 {
--tw-bg-opacity: 1;
background-color: rgb(249 250 251 / var(--tw-bg-opacity));
}
.p-4 { .p-4 {
padding: 1rem; padding: 1rem;
} }
@ -825,11 +851,6 @@ select {
padding-right: 1rem; padding-right: 1rem;
} }
.text-4xl {
font-size: 2.25rem;
line-height: 2.5rem;
}
.text-xl { .text-xl {
font-size: 1.25rem; font-size: 1.25rem;
line-height: 1.75rem; line-height: 1.75rem;
@ -840,13 +861,13 @@ select {
line-height: 1.75rem; line-height: 1.75rem;
} }
.font-semibold { .text-4xl {
font-weight: 600; font-size: 2.25rem;
line-height: 2.5rem;
} }
.text-white { .font-semibold {
--tw-text-opacity: 1; font-weight: 600;
color: rgb(255 255 255 / var(--tw-text-opacity));
} }
.shadow { .shadow {
@ -859,30 +880,63 @@ select {
text-decoration-line: underline; text-decoration-line: underline;
} }
.dark .dark\:border-white { @media (prefers-color-scheme: dark) {
.dark\:border-gray-700 {
--tw-border-opacity: 1;
border-color: rgb(55 65 81 / var(--tw-border-opacity));
}
.dark\:border-white {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(255 255 255 / var(--tw-border-opacity)); border-color: rgb(255 255 255 / var(--tw-border-opacity));
} }
.dark .dark\:bg-gray-900 { .dark\:bg-slate-800 {
--tw-bg-opacity: 1;
background-color: rgb(30 41 59 / var(--tw-bg-opacity));
}
.dark\:bg-gray-900 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(17 24 39 / var(--tw-bg-opacity)); background-color: rgb(17 24 39 / var(--tw-bg-opacity));
} }
.dark .dark\:bg-slate-700 { .dark\:bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
}
.dark\:bg-slate-700 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(51 65 85 / var(--tw-bg-opacity)); background-color: rgb(51 65 85 / var(--tw-bg-opacity));
} }
.dark .dark\:text-slate-300 { .dark\:text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.dark\:text-gray-900 {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.dark\:text-slate-300 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(203 213 225 / var(--tw-text-opacity)); color: rgb(203 213 225 / var(--tw-text-opacity));
} }
.dark .dark\:text-slate-400 { .dark\:text-slate-400 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(148 163 184 / var(--tw-text-opacity)); color: rgb(148 163 184 / var(--tw-text-opacity));
} }
}
@media (min-width: 640px) {
.sm\:h-9 {
height: 2.25rem;
}
}
@media (min-width: 768px) { @media (min-width: 768px) {
.md\:block { .md\:block {

View File

@ -11,12 +11,12 @@
<link rel="stylesheet" href="{% static 'base.css' %}" /> <link rel="stylesheet" href="{% static 'base.css' %}" />
</head> </head>
<body class="dark"> <body class="bg-white dark:bg-slate-800 dark:text-white">
<nav class="mb-4 bg-white dark:bg-gray-900 border-gray-200 rounded"> <nav class="mb-4 bg-white dark:bg-gray-900 border-gray-200 rounded">
<div class="container flex flex-wrap items-center justify-between mx-auto"> <div class="container flex flex-wrap items-center justify-between mx-auto">
<a href="#" class="flex items-center"> <a href="#" class="flex items-center">
<span class="text-4xl"></span> <span class="text-4xl"></span>
<span class="self-center text-xl font-semibold whitespace-nowrap text-white">Timetracker</span> <span class="self-center text-xl font-semibold whitespace-nowrap">Timetracker</span>
</a> </a>
<div class="w-full md:block md:w-auto"> <div class="w-full md:block md:w-auto">
<ul <ul

View File

@ -19,7 +19,6 @@ from django.views.generic import RedirectView
urlpatterns = [ urlpatterns = [
path("admin/", admin.site.urls),
path("", RedirectView.as_view(url="/tracker/list-sessions")), path("", RedirectView.as_view(url="/tracker/list-sessions")),
path("tracker/", include("tracker.urls")), path("tracker/", include("tracker.urls")),
] ]