summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChangjin Lee <changjin9792@gmail.com>2023-03-23 23:41:05 +0800
committerGitHub <noreply@github.com>2023-03-23 23:41:05 +0800
commit115f80652be90f1cce69bc3fb592e64ee26a85d6 (patch)
tree49aaefddd943f01ba1d596cf20768c968998acea
parent2e3d7e0c3ea5f790eec14d111538e244e779cf91 (diff)
parent2de7dd9c1eee94dcb58fa4bbf91e2b7576bf9f31 (diff)
Merge pull request #5 from noisrucer/developmain
Girok v0.1.2 release
-rwxr-xr-x.github/.gitmessage.txt23
-rwxr-xr-x.github/.pre-commit-config.yaml18
-rwxr-xr-x.github/ISSUE_TEMPLATE/README.md18
-rwxr-xr-x.github/ISSUE_TEMPLATE/bug-report.md15
-rw-r--r--.github/ISSUE_TEMPLATE/docs.md9
-rwxr-xr-x.github/ISSUE_TEMPLATE/extra.md11
-rwxr-xr-x.github/ISSUE_TEMPLATE/feature-request.md13
-rw-r--r--.github/ISSUE_TEMPLATE/refactor.md9
-rwxr-xr-x.github/commit_template_manual.md27
-rwxr-xr-x.github/pull_request_template.md29
-rw-r--r--.gitignore36
-rw-r--r--README.md1
-rw-r--r--dist/girok-0.1.0-py3-none-any.whlbin0 -> 35642 bytes
-rw-r--r--dist/girok-0.1.0.tar.gzbin0 -> 28634 bytes
-rw-r--r--dist/girok-0.1.1-py3-none-any.whlbin0 -> 35713 bytes
-rw-r--r--dist/girok-0.1.1.tar.gzbin0 -> 28690 bytes
-rw-r--r--dist/girok-0.1.2-py3-none-any.whlbin0 -> 35877 bytes
-rw-r--r--dist/girok-0.1.2.tar.gzbin0 -> 28749 bytes
-rw-r--r--girok/__init__.py1
-rw-r--r--girok/__main__.py0
-rw-r--r--girok/api/auth.py34
-rw-r--r--girok/api/category.py131
-rw-r--r--girok/api/task.py146
-rw-r--r--girok/calendar_cli/calendar_app.py37
-rw-r--r--girok/calendar_cli/calendar_container.py324
-rw-r--r--girok/calendar_cli/calendar_main.css252
-rw-r--r--girok/calendar_cli/calendar_main.py181
-rw-r--r--girok/calendar_cli/sidebar.py201
-rw-r--r--girok/calendar_cli/textual_demo_2023-03-11T22_49_21_681307.svg246
-rw-r--r--girok/commands/auth.py89
-rw-r--r--girok/commands/calendar.py10
-rw-r--r--girok/commands/category.py118
-rw-r--r--girok/commands/task.py569
-rw-r--r--girok/config.json4
-rw-r--r--girok/config.py22
-rw-r--r--girok/constants.py53
-rw-r--r--girok/girok.py43
-rw-r--r--girok/styles/stopwatch03.css53
-rw-r--r--girok/utils/__init__.py0
-rw-r--r--girok/utils/auth.py54
-rw-r--r--girok/utils/calendar.py132
-rw-r--r--girok/utils/display.py253
-rw-r--r--girok/utils/general.py52
-rw-r--r--girok/utils/task.py161
-rw-r--r--new_requirements.txt43
-rw-r--r--poetry.lock1277
-rw-r--r--processreq.py22
-rw-r--r--pyproject.toml59
-rw-r--r--tests/__init__.py0
49 files changed, 4775 insertions, 1 deletions
diff --git a/.github/.gitmessage.txt b/.github/.gitmessage.txt
new file mode 100755
index 0000000..9b99323
--- /dev/null
+++ b/.github/.gitmessage.txt
@@ -0,0 +1,23 @@
+################
+# Format: [Type] <Title>
+# Within 50 characters / Clearly indicate the changes / No period at the end
+# ex) [Feat] Add R-CNN Model
+# Write below
+
+# Do not delete the line below
+
+################
+# Write detailed description below
+# Use "-" for multiple lines (72 characters per line)
+
+################
+# Write footer below (issue number related to the current commit)
+# ex) issue #7
+
+################
+# Feat : New Feature
+# Fix : Bug Fix
+# Docs : Modify docs
+# Refact : Refactoring
+# Style : Changes that do not affect code logic
+################
diff --git a/.github/.pre-commit-config.yaml b/.github/.pre-commit-config.yaml
new file mode 100755
index 0000000..dcdb3d5
--- /dev/null
+++ b/.github/.pre-commit-config.yaml
@@ -0,0 +1,18 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v3.2.0
+ hooks:
+ - id: trailing-whitespace
+ - id: check-yaml
+ - id: check-json
+- repo: https://github.com/psf/black
+ rev: stable
+ hooks:
+ - id: black
+ language_version: python3.8
+- repo: https://gitlab.com/pycqa/flake8
+ rev: 4.0.1
+ hooks:
+ - id: flake8 \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/README.md b/.github/ISSUE_TEMPLATE/README.md
new file mode 100755
index 0000000..5cb1e9d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/README.md
@@ -0,0 +1,18 @@
+## Template Description
+
+ 1. Bug Report (BUG)
+ * To fix bugs during development
+
+ 2. Feature Request (Feat)
+ * Request new features
+
+ 3. Extra (EXT)
+ * Extra
+
+## Rules
+
+ 1. Common
+ * Title
+ * ex) [Feat] Develop user registration APIs
+ * Label
+ * Choose label according to the template
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
new file mode 100755
index 0000000..5cde92e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -0,0 +1,15 @@
+---
+name: Bug Report
+about: Bug Report Template
+title: ""
+labels: ""
+assignees: ""
+---
+
+## Bug Description
+
+## Bug Simulation
+
+## Error Message
+
+## Screenshots
diff --git a/.github/ISSUE_TEMPLATE/docs.md b/.github/ISSUE_TEMPLATE/docs.md
new file mode 100644
index 0000000..8801215
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/docs.md
@@ -0,0 +1,9 @@
+---
+name: Docs
+about: Documentation
+title: ""
+labels: ""
+assignees: ""
+---
+
+## Description
diff --git a/.github/ISSUE_TEMPLATE/extra.md b/.github/ISSUE_TEMPLATE/extra.md
new file mode 100755
index 0000000..3ee87a4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/extra.md
@@ -0,0 +1,11 @@
+---
+name: Extra
+about: Extra
+title: ""
+labels: ""
+assignees: ""
+---
+
+## Description
+
+## Comments
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100755
index 0000000..8dbadab
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,13 @@
+---
+name: Feature Request
+about: Template for requesting new features
+title: ""
+labels: ""
+assignees: ""
+---
+
+## Description
+
+## Purpose
+
+## Comments
diff --git a/.github/ISSUE_TEMPLATE/refactor.md b/.github/ISSUE_TEMPLATE/refactor.md
new file mode 100644
index 0000000..4805248
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/refactor.md
@@ -0,0 +1,9 @@
+---
+name: Refactor
+about: Refactor
+title: ""
+labels: ""
+assignees: ""
+---
+
+## Description
diff --git a/.github/commit_template_manual.md b/.github/commit_template_manual.md
new file mode 100755
index 0000000..15f89fe
--- /dev/null
+++ b/.github/commit_template_manual.md
@@ -0,0 +1,27 @@
+# Apply Commit Template Message
+
+Do `git clone` and you will see .gitmessage.txt
+
+๊ทธ ํ›„,<br>
+Do `git config --local commit.template .github/.gitmessage.txt`<br>
+to set the commit template.
+
+Now,<br>
+Do `git commit` when you commit instead of `git commit -m "message"`<br>
+
+After completing your commit, just close the commit file or<br>
+
+**โœ‹ For Linux bash or VSCode,**
+
+Type `Ctrl + x`<br>
+then you'll see save message, and type `y` to save it.
+
+If you type Enter, then commit is complete!
+
+**โœ‹ For git bash**
+
+Just do `:wq`
+
+<br>
+
+Then `git push`
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100755
index 0000000..ce3733e
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,29 @@
+## PR Description
+
+-
+
+<br>
+
+## Image (Optional)
+
+-
+
+<br>
+
+## Key Changes
+
+-
+
+<br>
+
+## Related Issue
+
+-
+
+<br>
+
+## To Reviewers
+
+-
+
+<br>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f1190bc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+.env
+**/__pycache__
+**/__pycache__/**
+# dependencies
+/node_modules/
+**/node_modules/
+/.pnp
+.pnp.js
+
+**/__pycache__
+**/.env
+/venv/
+**/venv/
+.idea/
+venv/
+.backend_venv/
+.cli_venv/
+.venv/
+**/.venv/
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/README.md b/README.md
index b087646..e69de29 100644
--- a/README.md
+++ b/README.md
@@ -1 +0,0 @@
-# girok-cli \ No newline at end of file
diff --git a/dist/girok-0.1.0-py3-none-any.whl b/dist/girok-0.1.0-py3-none-any.whl
new file mode 100644
index 0000000..fb2c24f
--- /dev/null
+++ b/dist/girok-0.1.0-py3-none-any.whl
Binary files differ
diff --git a/dist/girok-0.1.0.tar.gz b/dist/girok-0.1.0.tar.gz
new file mode 100644
index 0000000..0851a9d
--- /dev/null
+++ b/dist/girok-0.1.0.tar.gz
Binary files differ
diff --git a/dist/girok-0.1.1-py3-none-any.whl b/dist/girok-0.1.1-py3-none-any.whl
new file mode 100644
index 0000000..52d4501
--- /dev/null
+++ b/dist/girok-0.1.1-py3-none-any.whl
Binary files differ
diff --git a/dist/girok-0.1.1.tar.gz b/dist/girok-0.1.1.tar.gz
new file mode 100644
index 0000000..2ea2e29
--- /dev/null
+++ b/dist/girok-0.1.1.tar.gz
Binary files differ
diff --git a/dist/girok-0.1.2-py3-none-any.whl b/dist/girok-0.1.2-py3-none-any.whl
new file mode 100644
index 0000000..43623d5
--- /dev/null
+++ b/dist/girok-0.1.2-py3-none-any.whl
Binary files differ
diff --git a/dist/girok-0.1.2.tar.gz b/dist/girok-0.1.2.tar.gz
new file mode 100644
index 0000000..fdebf13
--- /dev/null
+++ b/dist/girok-0.1.2.tar.gz
Binary files differ
diff --git a/girok/__init__.py b/girok/__init__.py
new file mode 100644
index 0000000..48fef32
--- /dev/null
+++ b/girok/__init__.py
@@ -0,0 +1 @@
+__version__ = "0.1.2" \ No newline at end of file
diff --git a/girok/__main__.py b/girok/__main__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/girok/__main__.py
diff --git a/girok/api/auth.py b/girok/api/auth.py
new file mode 100644
index 0000000..6d71a38
--- /dev/null
+++ b/girok/api/auth.py
@@ -0,0 +1,34 @@
+import requests
+from girok.config import get_config
+cfg = get_config()
+
+base_url = cfg.base_url
+
+def register(email, password):
+ resp = requests.post(base_url + "/register", json={
+ "email": email,
+ "password": password
+ })
+ return resp
+
+
+def login(email, password):
+ files = {
+ "username": (None, email),
+ "password": (None, password)
+ }
+
+ resp = requests.post(base_url + "/login", files=files)
+ return resp
+
+
+def validate_access_token(access_token):
+ options = {
+ "headers": {
+ "Authorization": "Bearer " + access_token,
+ }
+ }
+
+
+ resp = requests.get(base_url + "/validate-access-token", headers=options['headers'])
+ return resp \ No newline at end of file
diff --git a/girok/api/category.py b/girok/api/category.py
new file mode 100644
index 0000000..f01d274
--- /dev/null
+++ b/girok/api/category.py
@@ -0,0 +1,131 @@
+import requests
+from rich.console import Console
+
+from girok.config import get_config
+import girok.utils.auth as auth_utils
+import girok.utils.general as general_utils
+import girok.utils.display as display_utils
+import girok.constants as constants
+
+console = Console()
+cfg = get_config()
+
+def get_categories():
+ resp = requests.get(
+ cfg.base_url + "/categories",
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+ if resp.status_code == 200:
+ return general_utils.bytes2dict(resp.content)
+
+
+
+def add_category(cat_str: str, color=None):
+ cats = cat_str.split('/')
+ resp = requests.post(
+ cfg.base_url + "/categories",
+ json={
+ "names": cats,
+ "color": color
+ },
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+ return resp
+
+
+def remove_category(cat_str: str):
+ cats = cat_str.split('/')
+ resp = requests.delete(
+ cfg.base_url + "/categories",
+ json={
+ "cats": cats
+ },
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+
+ return resp
+
+
+def rename_category(cat_str: str, new_name: str):
+ cats = cat_str.split('/')
+ resp = requests.patch(
+ cfg.base_url + "/categories/name",
+ json={
+ "cats": cats,
+ "new_name": new_name
+ },
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+
+ return resp
+
+
+def move_category(cat_str: str, new_parent_cat_str: str):
+ if cat_str.endswith('/'):
+ cat_str = cat_str[:-1]
+ if new_parent_cat_str.endswith('/'):
+ new_parent_cat_str = new_parent_cat_str[:-1]
+
+ cats = cat_str.split('/') if cat_str else []
+ new_parent_cats = new_parent_cat_str.split('/') if new_parent_cat_str else []
+ resp = requests.patch(
+ cfg.base_url + "/categories/parent",
+ json={
+ "cats": cats,
+ "new_parent_cats": new_parent_cats
+ },
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+ return resp
+
+
+def get_last_cat_id(cats: list):
+ resp = requests.get(
+ cfg.base_url + "/categories/last-cat-id",
+ json={
+ "cats": cats
+ },
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+ if resp.status_code == 200:
+ return general_utils.bytes2dict(resp.content)['cat_id']
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ exit(0)
+ else:
+ display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ exit(0)
+
+
+def get_category_color(cat_id: int):
+ resp = requests.get(
+ cfg.base_url + f"/categories/{cat_id}/color",
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+
+ if resp.status_code == 200:
+ return general_utils.bytes2dict(resp.content)['color']
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ exit(0)
+ else:
+ display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ exit(0)
+
+
+def get_color_dict():
+ resp = requests.get(
+ cfg.base_url + "/categories/color",
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+ if resp.status_code == 200:
+ color_dict = general_utils.bytes2dict(resp.content)
+ return color_dict
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ else:
+ display_utils.center_print("Error occurred.", constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ \ No newline at end of file
diff --git a/girok/api/task.py b/girok/api/task.py
new file mode 100644
index 0000000..04e972b
--- /dev/null
+++ b/girok/api/task.py
@@ -0,0 +1,146 @@
+from typing import Union
+from textual import log
+from datetime import datetime
+import requests
+
+from girok.config import get_config
+import girok.utils.auth as auth_utils
+import girok.utils.display as display_utils
+import girok.utils.general as general_utils
+import girok.utils.task as task_utils
+import girok.constants as constants
+
+cfg = get_config()
+
+def create_task(task_data: dict):
+ print(task_data)
+ resp = requests.post(
+ cfg.base_url + "/tasks",
+ json=task_data,
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+ if resp.status_code == 201:
+ task = general_utils.bytes2dict(resp.content)
+ task_id = task['task_id']
+ return task_id
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ else:
+ display_utils.center_print("Error occurred.", constants.DISPLAY_TERMINAL_COLOR_ERROR)
+
+
+def get_single_task(task_id: int):
+ resp = requests.get(
+ cfg.base_url + f"/tasks/{task_id}",
+ headers=auth_utils.build_jwt_header(cfg.config_path),
+ )
+ if resp.status_code == 200:
+ task = general_utils.bytes2dict(resp.content)
+ return task
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ else:
+ display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+
+
+
+def get_tasks(
+ cats: Union[list, None] = None,
+ start_date: Union[str, None] = None,
+ end_date: Union[str, None] = None,
+ tag: Union[str, None] = None,
+ priority: Union[int, None] = None,
+ no_priority: bool = False,
+ view: str = "category"
+):
+ query_str_obj = {
+ "category": cats,
+ "start_date": start_date,
+ "end_date": end_date,
+ "tag": tag,
+ "priority": priority,
+ "no_priority": no_priority,
+ "view": view
+ }
+ resp = requests.get(
+ cfg.base_url + "/tasks",
+ headers=auth_utils.build_jwt_header(cfg.config_path),
+ params=query_str_obj
+ )
+ return resp
+
+
+def remove_task(task_id: int):
+ resp = requests.delete(
+ cfg.base_url + f"/tasks/{task_id}",
+ headers=auth_utils.build_jwt_header(cfg.config_path),
+ )
+ return resp
+
+
+def get_tags():
+ resp = requests.get(
+ cfg.base_url + "/tasks/tags",
+ headers=auth_utils.build_jwt_header(cfg.config_path)
+ )
+
+ return resp
+
+
+def change_task_tag(task_id: int, new_tag_name: str):
+ resp = requests.patch(
+ cfg.base_url + f"/tasks/{task_id}/tag",
+ headers=auth_utils.build_jwt_header(cfg.config_path),
+ json={
+ "new_tag_name": new_tag_name
+ }
+ )
+
+ if resp.status_code == 204:
+ display_utils.center_print(f"Successfully renamed [ID: {task_id}] tag to {new_tag_name}.", "black on green")
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ else:
+ display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+
+
+def change_task_priority(task_id: int, new_priority: int):
+ resp = requests.patch(
+ cfg.base_url + f"/tasks/{task_id}/priority",
+ headers=auth_utils.build_jwt_header(cfg.config_path),
+ json={
+ "new_priority": new_priority
+ }
+ )
+
+ if resp.status_code == 204:
+ display_utils.center_print(f"Successfully change [ID: {task_id}] priority to {new_priority}.", "black on green")
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ else:
+ display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+
+
+def change_task_date(task_id: int, new_date: str):
+ resp = requests.patch(
+ cfg.base_url + f"/tasks/{task_id}/date",
+ headers=auth_utils.build_jwt_header(cfg.config_path),
+ json={
+ "new_date": new_date
+ }
+ )
+
+ if resp.status_code == 204:
+ display_utils.center_print(f"Successfully change [ID: {task_id}] date to {new_date}.", "black on green")
+ elif resp.status_code == 400:
+ err_msg = general_utils.bytes2dict(resp.content)['detail']
+ display_utils.center_print(err_msg, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+ else:
+ display_utils.center_print(resp.content, constants.DISPLAY_TERMINAL_COLOR_ERROR)
+
+
+
diff --git a/girok/calendar_cli/calendar_app.py b/girok/calendar_cli/calendar_app.py
new file mode 100644
index 0000000..443aba6
--- /dev/null
+++ b/girok/calendar_cli/calendar_app.py
@@ -0,0 +1,37 @@
+from textual.app import App, ComposeResult
+from textual.containers import Container, Horizontal, Vertical
+from textual.widgets import Button, Footer, Header, Static, Label, Placeholder, Tree
+from textual.messages import Message
+from textual.widget import Widget
+
+import girok.api.category as category_api
+import girok.utils.calendar as calendar_utils
+from rich.table import Table
+from rich.style import Style
+from textual import log
+
+from girok.calendar_cli.sidebar import SidebarContainer, CategoryTree
+from girok.calendar_cli.calendar_container import CalendarContainer
+import girok.constants as constants
+
+class CalendarApp(Horizontal):
+ CSS_PATH = "./demo_dock.css"
+
+ def compose(self):
+ yield SidebarContainer(id="sidebar-container")
+ yield CalendarContainer(id="calendar-container")
+
+ def on_category_tree_category_changed(self, event):
+ self.query_one(CalendarContainer).update_cat_path(event.cat_path)
+ cat_tree = self.query_one(CategoryTree)
+
+ def on_tag_tree_tag_changed(self, event):
+ tag = event.tag
+ if tag.endswith(" " + constants.LEFT_ARROW_EMOJI):
+ tag = tag[:-2]
+ if tag == "All Tags":
+ tag = ""
+ self.query_one(CalendarContainer).update_tag(tag)
+
+ def on_category_tree_custom_test_message(self, event):
+ self.refresh() \ No newline at end of file
diff --git a/girok/calendar_cli/calendar_container.py b/girok/calendar_cli/calendar_container.py
new file mode 100644
index 0000000..38d54c9
--- /dev/null
+++ b/girok/calendar_cli/calendar_container.py
@@ -0,0 +1,324 @@
+import asyncio
+from datetime import datetime, timedelta
+import calendar
+
+from textual.app import App, ComposeResult
+from textual.containers import Container, Horizontal, Vertical
+from textual.widgets import Button, Footer, Header, Static, Label, Placeholder, Tree, DataTable
+from textual.messages import Message
+from textual.widget import Widget
+from textual.reactive import var
+from rich.text import Text
+from rich.style import Style
+from rich.segment import Segment
+from rich.panel import Panel
+from rich.markdown import Markdown
+from textual import log
+
+import girok.api.task as task_api
+import girok.api.category as category_api
+import girok.utils.calendar as calendar_utils
+import girok.utils.general as general_utils
+import girok.utils.task as task_utils
+import girok.constants as constants
+from girok.calendar_cli.sidebar import CategoryTree, TagTree
+
+
+class WeekdayBarContainer(Horizontal):
+ pass
+
+class CalendarHeader(Vertical):
+ year = datetime.now().year
+ month = datetime.now().month
+ cat_path = ""
+ tag = ""
+
+ def on_mount(self):
+ self.display_date()
+
+ def compose(self):
+ month_name = task_utils.get_month_name_by_number(self.month)
+
+ with Horizontal():
+ with Container(id="calendar-header-category-container"):
+ yield Static(self.cat_path, id="calendar-header-category")
+ with Container(id="calendar-header-date-container"):
+ yield Static(Text(f"{month_name} {self.year}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR, bold=True)), id="calendar-header-date")
+ with Container(id="calendar-header-tag-container"):
+ yield Static(f"{self.tag}", id="calendar-header-tag")
+ yield Horizontal()
+ with WeekdayBarContainer(id="weekday-bar"):
+ yield Static(Text("Monday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name")
+ yield Static(Text("Tuesday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name")
+ yield Static(Text("Wednesday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name")
+ yield Static(Text("Thursday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name")
+ yield Static(Text("Friday", style=Style(color=constants.CALENDAR_WEEKDAY_NAME_COLOR, bold=True)), classes="calendar-weekday-name")
+ yield Static(Text("Saturday", style=Style(color="#87C5FA", bold=True)), classes="calendar-weekday-name")
+ yield Static(Text("Sunday", style=Style(color="#DB4455", bold=True)), classes="calendar-weekday-name")
+
+ def update_year_and_month(self, year, month):
+ self.year, self.month = year, month
+ self.display_date()
+
+ def update_cat_path(self, new_cat_path):
+ self.cat_path = new_cat_path
+ self.display_date()
+
+ def update_tag(self, new_tag):
+ self.tag = new_tag
+ self.display_date()
+
+ def display_date(self):
+ month_name = task_utils.get_month_name_by_number(self.month, abbr=False)
+ calendar_header_category = self.query_one("#calendar-header-category")
+ calendar_header_date = self.query_one("#calendar-header-date")
+ calendar_header_tag = self.query_one("#calendar-header-tag")
+ calendar_weekday_bar = self.query_one("#weekday-bar")
+
+ calendar_header_category.update(Text(f"Category: /{self.cat_path}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR)))
+ calendar_header_date.update(Text(f"{month_name} {self.year}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR, bold=True)))
+ calendar_header_tag.update(Text(f"Tag: {self.tag}", style=Style(color=constants.CALENDAR_HEADER_DATE_COLOR)))
+
+
+class CalendarCell(Vertical):
+ pass
+
+
+class Calendar(Container):
+ year = datetime.now().year
+ month = datetime.now().month
+ cat_path = "" # If "", show all categories
+ tag = ""
+ tasks = []
+ can_focus = True
+ cur_month_first_day_cell_num = None
+ cur_focused_cell_cord = (None, None)
+ cur_focused_cell = None
+ m = 5
+ n = 7
+ grid = [[False for _ in range(7)] for _ in range(5)]
+ is_pop_up = False
+
+ class TaskCellSelected(Message):
+ def __init__(self, cell_tasks, year, month, day):
+ super().__init__()
+ self.cell_tasks = cell_tasks
+ self.year = year
+ self.month = month
+ self.day = day
+
+ def on_mount(self