diff --git a/khaikang/settings.py b/khaikang/settings.py
index e2cf6d6..e6d3f30 100644
--- a/khaikang/settings.py
+++ b/khaikang/settings.py
@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/4.1/ref/settings/
"""
from pathlib import Path
+import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -117,7 +118,8 @@ USE_TZ = True
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = 'static/'
-STATIC_ROOT = '/home/kiantin1/public_html/khaikang/static/'
+STATICFILES_DIRS= [os.path.join(BASE_DIR, 'static')] # test only
+# STATIC_ROOT = '/home/kiantin1/public_html/khaikang/static/' deploy only
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
diff --git a/khaikang/urls.py b/khaikang/urls.py
index f3df2dc..4a309eb 100644
--- a/khaikang/urls.py
+++ b/khaikang/urls.py
@@ -28,3 +28,4 @@ urlpatterns = [
path('api/get_latest_posts', views.api_get_latest_posts),
path('api/get_previous_posts', views.api_get_previous_posts),
]
+
diff --git a/static/admin/css/dark_mode.css b/static/admin/css/dark_mode.css
new file mode 100644
index 0000000..547717c
--- /dev/null
+++ b/static/admin/css/dark_mode.css
@@ -0,0 +1,33 @@
+@media (prefers-color-scheme: dark) {
+ :root {
+ --primary: #264b5d;
+ --primary-fg: #f7f7f7;
+
+ --body-fg: #eeeeee;
+ --body-bg: #121212;
+ --body-quiet-color: #e0e0e0;
+ --body-loud-color: #ffffff;
+
+ --breadcrumbs-link-fg: #e0e0e0;
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #81d4fa;
+ --link-hover-color: #4ac1f7;
+ --link-selected-fg: #6f94c6;
+
+ --hairline-color: #272727;
+ --border-color: #353535;
+
+ --error-fg: #e35f5f;
+ --message-success-bg: #006b1b;
+ --message-warning-bg: #583305;
+ --message-error-bg: #570808;
+
+ --darkened-bg: #212121;
+ --selected-bg: #1b1b1b;
+ --selected-row: #00363a;
+
+ --close-button-bg: #333333;
+ --close-button-hover-bg: #666666;
+ }
+ }
diff --git a/static/admin/js/filters.js b/static/admin/js/filters.js
new file mode 100644
index 0000000..ba691ac
--- /dev/null
+++ b/static/admin/js/filters.js
@@ -0,0 +1,30 @@
+/**
+ * Persist changelist filters state (collapsed/expanded).
+ */
+'use strict';
+{
+ // Init filters.
+ let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState'));
+
+ if (!filters) {
+ filters = {};
+ }
+
+ Object.entries(filters).forEach(([key, value]) => {
+ const detailElement = document.querySelector(`[data-filter-title='${key}']`);
+
+ // Check if the filter is present, it could be from other view.
+ if (detailElement) {
+ value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open');
+ }
+ });
+
+ // Save filter state when clicks.
+ const details = document.querySelectorAll('details');
+ details.forEach(detail => {
+ detail.addEventListener('toggle', event => {
+ filters[`${event.target.dataset.filterTitle}`] = detail.open;
+ sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters));
+ });
+ });
+}
diff --git a/static/timeline.js b/static/timeline.js
new file mode 100644
index 0000000..af197b2
--- /dev/null
+++ b/static/timeline.js
@@ -0,0 +1,178 @@
+
+timezoneChangingOne = (x)=>{var date= new Date(x.innerHTML);
+ var year = date.getFullYear().toString();
+ var month = (date.getMonth()+1).toString().padStart(2, '0');
+ var day = date.getDate().toString().padStart(2, '0');
+ var hour = date.getHours().toString().padStart(2, '0');
+ var min = date.getMinutes().toString().padStart(2, '0');
+ var sec = date.getSeconds().toString().padStart(2, '0');
+ local_date_string = `${year}-${month}-${day} ${hour}:${min}:${sec}`;
+ x.innerHTML=local_date_string;}
+
+function timezoneChanging(){
+document.querySelectorAll(".post-time").forEach(
+x => timezoneChangingOne(x)
+ );
+}
+
+
+
+$name = (x) => document.getElementsByName(x);
+$ = (x) => document.getElementById(x);
+var httpRequest;
+$("submit_post").addEventListener('click', make_req);
+
+async function make_req() {
+
+post_text = $('post_text').value;
+post_privilage = $('privil_choosing').value;
+
+if (post_text != ""){
+
+await fetch('/api/post', {
+method: 'POST',
+headers: {
+"X-CSRFToken": "{{ csrf_token }}",
+'Content-Type': 'application/json',
+},
+body: JSON.stringify({
+"privilage" : post_privilage,
+"text": post_text,
+})
+
+}).then(response => {if (response.ok == true)
+{$('post_text').value = "";
+getLatestPosts(); // wait for a moment then get latest posts
+}}
+
+);
+}
+
+
+
+}
+
+function auto_expand(element) {
+element.style.height = 6+"em";
+element.style.height = (element.scrollHeight)+"px";
+}
+
+timezoneChanging();
+
+function adjust_post_text(){
+var post_text = $("post_text");
+post_text.style.height = 6+"em";
+post_text.style.height = (post_text.scrollHeight)+"px";
+}
+
+
+async function getRecentPostsCounter(){
+latest_time_string = $("latest_time").innerHTML;
+await fetch('/api/get_recent_posts_counter', {
+method: 'POST',
+headers: {
+"X-CSRFToken": "{{ csrf_token }}",
+'Content-Type': 'application/json',
+},
+body: JSON.stringify({
+"latest_time" : latest_time_string,
+})
+
+}).then(response => response.json())
+.then(the_json => {console.log(the_json);let newer_posts_num = the_json['newer_posts_num'];
+if (newer_posts_num == 1)
+{ $("new_post_notifier").style.display = "block";
+$("new_post_notifier").innerHTML = `1 new post`}
+if (newer_posts_num > 1)
+{ $("new_post_notifier").style.display = "block";
+$("new_post_notifier").innerHTML = `${newer_posts_num} new posts`} });
+
+}
+
+var intervalID = window.setInterval(getRecentPostsCounter, 20000);
+
+function appendPostToTheEnd(post){
+var public_tl = $("public_timeline");
+var new_div = createPostDiv(post);
+
+
+public_tl.insertBefore(new_div, $('previous_post_loader'));
+}
+
+async function getPreviousPosts(){
+var new_oldest_time;
+oldest_time_string = $("oldest_time").innerHTML;
+await fetch('/api/get_previous_posts', {
+method: 'POST',
+headers: {
+"X-CSRFToken": "{{ csrf_token }}",
+'Content-Type': 'application/json',
+},
+body: JSON.stringify({
+"oldest_time" : oldest_time_string,
+}) }).then(response => response.json())
+.then(item => {new_oldest_time_raw = item['oldest_time'];
+ new_oldest_time = new_oldest_time_raw.substring(0,10) + " " + new_oldest_time_raw.substring(11,26) + "+0000";
+ return item['older_posts'];})
+.then(posts => {if (posts.length == 0)
+ {$('previous_post_loader').style.display = 'none';}
+ else{posts.forEach(post => appendPostToTheEnd(post));
+ $('oldest_time').innerHTML = new_oldest_time;}})
+}
+
+
+async function getLatestPosts(){
+latest_time_string = $("latest_time").innerHTML;
+await fetch('/api/get_latest_posts', {
+method: 'POST',
+headers: {
+"X-CSRFToken": "{{ csrf_token }}",
+'Content-Type': 'application/json',
+},
+body: JSON.stringify({
+"latest_time" : latest_time_string,
+}) }).then(response => response.json())
+.then(item => item['newer_posts'])
+.then(posts => {posts.forEach(post => addPostToTheBeginning(post));
+$('new_post_notifier').style.display = "none";
+var nowTime = new Date();
+var nowTimeString = nowTime.toISOString();
+$("latest_time").innerHTML = nowTimeString.substring(0,10) + " " + nowTimeString.substring(11,23) + "000+0000"; });
+}
+
+function createPostDiv(post){
+
+var new_div = document.createElement("div");
+new_div.id = `post-${post.id}`;
+new_div.className = "post";
+post_text_replaced = post.text.replace(/(\r\n|\n\r|\r|\n)/g, "
" );
+console.log(post_text_replaced);
+new_div.innerHTML = `${post.poster_shown_name}
+at ${post.post_time}
+${post_text_replaced}
+
+- đ
+- â`;
+
+new_div_timestamp = new_div.getElementsByClassName('post-time')[0];
+
+timezoneChangingOne(new_div_timestamp);
+
+return new_div;
+}
+
+function addPostToTheBeginning(post){
+var public_tl = $("public_timeline");
+var new_div = createPostDiv(post);
+
+
+public_tl.insertBefore(new_div, $('latest_time').nextSibling);
+
+}
+
+$("new_post_notifier").addEventListener('click', getLatestPosts);
+$("previous_post_loader").addEventListener('click', getPreviousPosts);
+
+
+
+adjust_post_text();
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
index 0324c3a..4a39a62 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -1,7 +1,12 @@
{% extends "base_generic.html" %}
-
+{% load static %}
{% load tz %}
+
{% get_current_timezone as TIME_ZONE %}
+{% block headbar %}
+{{ request.user.shown_name }} (My timeline) - Configs - Log out
+{% endblock %}
+
{% block content %}