Diff between 693fedd58be44ba7e645dace02c82bf5f2a970c9 and b8e80e6f7013d57c5df8f52714f75d39bf2151d5

Changed Files

File Additions Deletions Status
internal/database/queries.go +9 -8 modified
web/static/aurinko.svg +1 -0 added
web/static/kuu.svg +1 -0 added
web/static/styles.css +85 -0 modified
web/static/theme.js +37 -0 added
web/static/tupru.png +0 -0 added
web/static/urho.avif +0 -0 added
web/templates/index.html +20 -5 modified

Full Patch

diff --git a/internal/database/queries.go b/internal/database/queries.go
index a71c720..828d3d4 100644
--- a/internal/database/queries.go
+++ b/internal/database/queries.go
@@ -7,11 +7,12 @@ import (
 )
 
 type Article struct {
-	Id         int
-	Title      string
-	Content    string
-	Picture    string
-	CategoryId string
+	Id          int
+	Title       string
+	Content     string
+	Picture     string
+	CategoryId  string
+	Description string
 }
 
 type Category struct {
@@ -29,7 +30,7 @@ func GetArticles(db *sql.DB) ([]Article, error) {
 	for rows.Next() {
 		article := Article{}
 		var category_id sql.NullString
-		if err := rows.Scan(&article.Id, &article.Title, &article.Content, &article.Picture, &category_id); err != nil {
+		if err := rows.Scan(&article.Id, &article.Title, &article.Content, &article.Picture, &category_id, &article.Description); err != nil {
 			return nil, err
 		}
 		if category_id.Valid {
@@ -60,7 +61,7 @@ func GetCategories(db *sql.DB) ([]Category, error) {
 }
 
 func GetCategoryArticles(db *sql.DB, category string) ([]Article, error) {
-	stmtOut, err := db.Prepare("SELECT article_id, article_title, article_content, article_picture FROM articles INNER JOIN categories ON articles.category_id = categories.category_id WHERE category_name = ?;")
+	stmtOut, err := db.Prepare("SELECT article_id, article_title, article_content, article_picture, article_description FROM articles INNER JOIN categories ON articles.category_id = categories.category_id WHERE category_name = ?;")
 	if err != nil {
 		return nil, err
 	}
@@ -74,7 +75,7 @@ func GetCategoryArticles(db *sql.DB, category string) ([]Article, error) {
 
 	for rows.Next() {
 		article := Article{}
-		if err := rows.Scan(&article.Id, &article.Title, &article.Content, &article.Picture); err != nil {
+		if err := rows.Scan(&article.Id, &article.Title, &article.Content, &article.Picture, &article.Description); err != nil {
 			return nil, err
 		}
 		articles = append(articles, article)
diff --git a/web/static/aurinko.svg b/web/static/aurinko.svg
new file mode 100644
index 0000000..65c97c7
--- /dev/null
+++ b/web/static/aurinko.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-sun-icon lucide-sun"><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></svg>
\ No newline at end of file
diff --git a/web/static/kuu.svg b/web/static/kuu.svg
new file mode 100644
index 0000000..07b397d
--- /dev/null
+++ b/web/static/kuu.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-moon-icon lucide-moon"><path d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"/></svg>
\ No newline at end of file
diff --git a/web/static/styles.css b/web/static/styles.css
index 6ca6800..4fd57db 100644
--- a/web/static/styles.css
+++ b/web/static/styles.css
@@ -1,3 +1,88 @@
 * {
     font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+}
+
+:root {
+    --default-text: light-dark(black, white);
+    --background: light-dark(#f8f8f8, rgb(20, 20, 20));
+    --card: light-dark(white, rgb(52, 52, 52));
+}
+
+[data-theme="light"] {
+    color-scheme: light;
+}
+
+[data-theme="dark"] {
+    color-scheme: dark;
+}
+
+body {
+    background-color: var(--background);
+    margin: 0;
+}
+
+main {
+    max-width: 1000px;
+    margin: auto;
+    padding: 20px;
+}
+
+a {
+    color: var(--default-text);
+    text-decoration: none;
+}
+
+nav {
+    height: fit-content;
+}
+
+.uutis-lista {
+    display: grid;
+    gap: 10px;
+    grid-template-columns: repeat(2, 1fr);
+    grid-auto-rows: 1fr;
+}
+
+.uutis-kortti {
+    display: flex;
+    flex-direction: column;
+    background-color: var(--card);
+    transition: box-shadow 0.2s;
+    min-height: 100%;
+}
+
+.uutis-kortti:hover {
+    box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.01), 0 2px 20px 0 rgba(0, 0, 0, 0.05);
+}
+
+.uutis-kuva {
+    object-fit: cover; 
+    aspect-ratio: 16/9;
+    width: 495px;
+}
+
+.uutis-tiedot {
+    padding: 10px 20px;
+}
+
+header {
+    background-color: var(--card);
+    padding: 20px;
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    gap: 200px;
+    align-items: center;
+}
+
+.theme-button {
+    border: none;
+    background: none;
+}
+
+.theme-button .dark- {
+    filter: invert(0);
+}
+.theme-button .light {
+    filter: invert(1);
 }
\ No newline at end of file
diff --git a/web/static/theme.js b/web/static/theme.js
new file mode 100644
index 0000000..055f44c
--- /dev/null
+++ b/web/static/theme.js
@@ -0,0 +1,37 @@
+document.addEventListener('DOMContentLoaded', function() {
+	const themeButton = document.getElementById("theme-button");
+	loadTheme(themeButton);
+	themeButton.addEventListener('click', () => {
+		if (theme === "dark") {
+			setTheme("light", themeButton)
+			theme = "light"
+		} else {
+			setTheme("dark", themeButton)
+			theme = "dark"
+		}
+	});
+})
+const html = document.documentElement;
+
+let theme
+const setTheme = (theme, btn) => {
+   document.documentElement.removeAttribute('data-theme');
+
+   if (theme === 'dark') {
+	   html.setAttribute('data-theme', 'dark');
+	   btn.innerHTML = "<img src='/static/aurinko.svg' class='light' />"
+	} else {
+		btn.innerHTML = "<img src='/static/kuu.svg' class='dark' />"
+	}
+	
+	localStorage.setItem('theme', theme);
+};
+
+const loadTheme = (btn) => {
+  const savedTheme = localStorage.getItem('theme');
+  theme = savedTheme
+  if (savedTheme) {
+	  setTheme(savedTheme, btn);
+	}
+};
+
diff --git a/web/static/tupru.png b/web/static/tupru.png
new file mode 100644
index 0000000..394e855
Binary files /dev/null and b/web/static/tupru.png differ
diff --git a/web/static/urho.avif b/web/static/urho.avif
new file mode 100644
index 0000000..c5ffa2e
Binary files /dev/null and b/web/static/urho.avif differ
diff --git a/web/templates/index.html b/web/templates/index.html
index 716dbc7..5bb49d7 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -4,11 +4,12 @@
 	<meta charset="UTF-8">
 	<meta name="viewport" content="width=device-width, initial-scale=1.0">
 	<title>Uutissivusto</title>
+	<script src="/static/theme.js"></script>
 	<link rel="stylesheet" href="/static/styles.css">
 </head>
 <body>
 	<header>
-        <nav style="display: flex; gap: 15px;">
+        <nav style="display: flex; gap: 20px;">
             <a href="/">
                 Uutiset
             </a>
@@ -20,13 +21,27 @@
             </a>
         </nav>
         <nav id="theme-nav">
-            <button id="theme-button" class="theme-button">
+            <button id="theme-button" class="theme-button">mirri
             </button>
         </nav>
     </header>
-	{{range .Articles}}
-		{{ .}}<br />
-	{{end}}
+	<main class="uutis-lista">
+			{{range .Articles}}
+			<a href="{{.Title}}">
+				<article class="uutis-kortti">
+					<img src="{{.Picture}}" class="uutis-kuva">
+					<div class="uutis-tiedot">
+						<h2>
+							{{ .Title }}
+						</h2>
+						<p>
+							{{.Description}}
+						</p>
+					</div>
+				</article>
+			</a>
+			{{end}}
+		</main>
 </body>
 </html>
 {{ end }}
\ No newline at end of file