clean up UI on drive viewer
This commit is contained in:
@@ -30,6 +30,9 @@ from textual.worker import Worker, get_current_worker
|
|||||||
from textual import work
|
from textual import work
|
||||||
from textual.widgets.option_list import Option
|
from textual.widgets.option_list import Option
|
||||||
|
|
||||||
|
# Import file icons utility - note the updated import
|
||||||
|
from utils.file_icons import get_file_icon
|
||||||
|
|
||||||
# Import our DocumentViewerScreen
|
# Import our DocumentViewerScreen
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), "maildir_gtd"))
|
sys.path.append(os.path.join(os.path.dirname(__file__), "maildir_gtd"))
|
||||||
from maildir_gtd.screens.DocumentViewer import DocumentViewerScreen
|
from maildir_gtd.screens.DocumentViewer import DocumentViewerScreen
|
||||||
@@ -96,26 +99,24 @@ class OneDriveTUI(App):
|
|||||||
yield Header(show_clock=True)
|
yield Header(show_clock=True)
|
||||||
|
|
||||||
with Container(id="main_container"):
|
with Container(id="main_container"):
|
||||||
yield LoadingIndicator(id="loading")
|
with Horizontal(id="top_bar"):
|
||||||
yield Label("Authenticating with Microsoft Graph API...", id="status_label")
|
yield Button("\uf148 Up", id="back_button", classes="hide")
|
||||||
|
yield Label("Authenticating with Microsoft Graph API...", id="status_label")
|
||||||
|
yield LoadingIndicator(id="loading")
|
||||||
|
yield OptionList(
|
||||||
|
Option("Following", id="following"),
|
||||||
|
Option("Root", id="root"),
|
||||||
|
id="view_options"
|
||||||
|
)
|
||||||
|
|
||||||
with Container(id="auth_container"):
|
with Container(id="auth_container"):
|
||||||
yield Label("", id="auth_message")
|
yield Label("", id="auth_message")
|
||||||
yield Button("Login", id="login_button", variant="primary")
|
yield Button("Login", id="login_button", variant="primary")
|
||||||
|
|
||||||
with Container(id="content_container", classes="hide"):
|
with Container(id="content_container", classes="hide"):
|
||||||
with Horizontal():
|
with Vertical(id="items_container"):
|
||||||
with Vertical(id="navigation_container"):
|
yield DataTable(id="items_table")
|
||||||
|
yield Label("No items found", id="no_items_label", classes="hide")
|
||||||
yield OptionList(
|
|
||||||
Option("Following", id="following"),
|
|
||||||
Option("Root", id="root"),
|
|
||||||
id="view_options"
|
|
||||||
)
|
|
||||||
|
|
||||||
with Vertical(id="items_container"):
|
|
||||||
yield DataTable(id="items_table")
|
|
||||||
yield Label("No items found", id="no_items_label", classes="hide")
|
|
||||||
|
|
||||||
yield Footer()
|
yield Footer()
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ class OneDriveTUI(App):
|
|||||||
# Initialize the table
|
# Initialize the table
|
||||||
table = self.query_one("#items_table")
|
table = self.query_one("#items_table")
|
||||||
table.cursor_type = "row"
|
table.cursor_type = "row"
|
||||||
table.add_columns("Type", "Name", "Last Modified", "Size", "Web URL")
|
table.add_columns("◇", "Name", "Last Modified", "Size", "Web URL")
|
||||||
|
|
||||||
# Load cached token if available
|
# Load cached token if available
|
||||||
if os.path.exists(self.cache_file):
|
if os.path.exists(self.cache_file):
|
||||||
@@ -183,6 +184,8 @@ class OneDriveTUI(App):
|
|||||||
|
|
||||||
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
"""Handle button presses."""
|
"""Handle button presses."""
|
||||||
|
if event.button.id == "back_button":
|
||||||
|
self.action_navigate_back()
|
||||||
if event.button.id == "login_button":
|
if event.button.id == "login_button":
|
||||||
self.initiate_device_flow()
|
self.initiate_device_flow()
|
||||||
|
|
||||||
@@ -275,7 +278,7 @@ class OneDriveTUI(App):
|
|||||||
elif selected_option == "root":
|
elif selected_option == "root":
|
||||||
self.current_view = "Root"
|
self.current_view = "Root"
|
||||||
if self.selected_drive_id:
|
if self.selected_drive_id:
|
||||||
self.load_root_items()
|
self.load_drive_folder_items()
|
||||||
|
|
||||||
async def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
|
async def on_data_table_row_selected(self, event: DataTable.RowSelected) -> None:
|
||||||
"""Handle row selection in the items table."""
|
"""Handle row selection in the items table."""
|
||||||
@@ -287,6 +290,7 @@ class OneDriveTUI(App):
|
|||||||
|
|
||||||
def open_item(self, selected_id: str):
|
def open_item(self, selected_id: str):
|
||||||
if selected_id:
|
if selected_id:
|
||||||
|
self.folder_history.append(FolderHistoryEntry(self.current_folder_id, self.current_folder_name, self.selected_drive_id))
|
||||||
# Get an item from current items by ID string
|
# Get an item from current items by ID string
|
||||||
selected_row = self.current_items[selected_id]
|
selected_row = self.current_items[selected_id]
|
||||||
|
|
||||||
@@ -294,19 +298,19 @@ class OneDriveTUI(App):
|
|||||||
|
|
||||||
# Check if it's a folder
|
# Check if it's a folder
|
||||||
is_folder = bool(selected_row.get("folder"))
|
is_folder = bool(selected_row.get("folder"))
|
||||||
|
|
||||||
if is_folder:
|
if is_folder:
|
||||||
self.notify(f"Selected folder: {item_name}")
|
self.notify(f"Selected folder: {item_name}", timeout=1)
|
||||||
# Load items in the folder
|
# Load items in the folder
|
||||||
|
self.query_one("#back_button").remove_class("hide")
|
||||||
self.query_one("#status_label").update(f"Loading items in folder: {item_name}")
|
self.query_one("#status_label").update(f"Loading items in folder: {item_name}")
|
||||||
self.load_root_items(folder_id=selected_id, drive_id=selected_row.get("parentReference", {}).get("driveId", self.selected_drive_id))
|
self.load_drive_folder_items(folder_id=selected_id, drive_id=selected_row.get("parentReference", {}).get("driveId", self.selected_drive_id))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.notify(f"Selected file: {item_name}")
|
self.notify(f"Selected file: {item_name}")
|
||||||
self.action_view_document()
|
self.action_view_document()
|
||||||
|
|
||||||
@work
|
@work
|
||||||
async def load_root_items(self, folder_id: str = "", drive_id: str = "", track_history: bool = True):
|
async def load_drive_folder_items(self, folder_id: str = "", drive_id: str = "", track_history: bool = True):
|
||||||
"""Load root items from the selected drive."""
|
"""Load root items from the selected drive."""
|
||||||
if not self.access_token or not self.selected_drive_id:
|
if not self.access_token or not self.selected_drive_id:
|
||||||
return
|
return
|
||||||
@@ -315,10 +319,10 @@ class OneDriveTUI(App):
|
|||||||
headers = {"Authorization": f"Bearer {self.access_token}"}
|
headers = {"Authorization": f"Bearer {self.access_token}"}
|
||||||
url = f"https://graph.microsoft.com/v1.0/me/drive/root/children"
|
url = f"https://graph.microsoft.com/v1.0/me/drive/root/children"
|
||||||
|
|
||||||
if folder_id and drive_id:
|
if folder_id and drive_id and folder_id != "root":
|
||||||
url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/items/{folder_id}/children"
|
url = f"https://graph.microsoft.com/v1.0/drives/{drive_id}/items/{folder_id}/children"
|
||||||
if track_history:
|
# if track_history:
|
||||||
self.folder_history.append(FolderHistoryEntry(folder_id, self.current_folder_name, drive_id))
|
# self.folder_history.append(FolderHistoryEntry(folder_id, self.current_folder_name, drive_id))
|
||||||
self.selected_drive_id = drive_id
|
self.selected_drive_id = drive_id
|
||||||
self.current_folder_id = folder_id
|
self.current_folder_id = folder_id
|
||||||
self.current_folder_name = self.current_items[folder_id].get("name", "Unknown")
|
self.current_folder_name = self.current_items[folder_id].get("name", "Unknown")
|
||||||
@@ -338,7 +342,13 @@ class OneDriveTUI(App):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.notify(f"Error loading root items: {str(e)}", severity="error")
|
self.notify(f"Error loading root items: {str(e)}", severity="error")
|
||||||
|
|
||||||
self.query_one("#status_label").update("Ready")
|
#update the status label with breadcrumbs from the folder_history
|
||||||
|
if self.folder_history:
|
||||||
|
breadcrumbs = " / \uf07b ".join([entry.folder_name for entry in self.folder_history])
|
||||||
|
self.query_one("#status_label").update(f"\uf07b {breadcrumbs} / \uf07b {self.current_folder_name}")
|
||||||
|
else:
|
||||||
|
self.query_one("#status_label").update(f" \uf07b {self.current_folder_name}")
|
||||||
|
|
||||||
|
|
||||||
@work
|
@work
|
||||||
async def load_followed_items(self):
|
async def load_followed_items(self):
|
||||||
@@ -384,9 +394,8 @@ class OneDriveTUI(App):
|
|||||||
name = item.get("name", "Unknown")
|
name = item.get("name", "Unknown")
|
||||||
is_folder = bool(item.get("folder"))
|
is_folder = bool(item.get("folder"))
|
||||||
|
|
||||||
# Add folder icon if it's a folder and we're in root view
|
# Get icon for the file type
|
||||||
|
item_type = get_file_icon(name, is_folder)
|
||||||
item_type = "📁" if is_folder else "📄"
|
|
||||||
|
|
||||||
# Format the last modified date
|
# Format the last modified date
|
||||||
last_modified = item.get("lastModifiedDateTime", "")
|
last_modified = item.get("lastModifiedDateTime", "")
|
||||||
@@ -413,9 +422,21 @@ class OneDriveTUI(App):
|
|||||||
|
|
||||||
web_url = item.get("webUrl", "")
|
web_url = item.get("webUrl", "")
|
||||||
item_id = item.get("id")
|
item_id = item.get("id")
|
||||||
item_drive_id = item.get("parentReference", {}).get("driveId", self.selected_drive_id)
|
|
||||||
row_key = table.add_row(item_type, name, last_modified, size_str, web_url, key=item.get("id"))
|
# Limit filename length to 160 characters
|
||||||
# add item to to the list of current items keyed by row_key so we can look up all information later
|
display_name = name[:50] + '...' if len(name) > 50 else name
|
||||||
|
|
||||||
|
# Add row to table with the appropriate icon class for styling
|
||||||
|
row_key = table.add_row(
|
||||||
|
item_type,
|
||||||
|
display_name,
|
||||||
|
last_modified,
|
||||||
|
size_str,
|
||||||
|
web_url,
|
||||||
|
key=item.get("id")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add item to the list of current items keyed by row_key so we can look up all information later
|
||||||
self.current_items[row_key] = item
|
self.current_items[row_key] = item
|
||||||
|
|
||||||
async def action_next_view(self) -> None:
|
async def action_next_view(self) -> None:
|
||||||
@@ -424,7 +445,7 @@ class OneDriveTUI(App):
|
|||||||
if self.current_view == "Following":
|
if self.current_view == "Following":
|
||||||
option_list.highlighted = 1 # Switch to Root
|
option_list.highlighted = 1 # Switch to Root
|
||||||
self.current_view = "Root"
|
self.current_view = "Root"
|
||||||
self.load_root_items()
|
self.load_drive_folder_items()
|
||||||
else:
|
else:
|
||||||
option_list.highlighted = 0 # Switch to Following
|
option_list.highlighted = 0 # Switch to Following
|
||||||
self.current_view = "Following"
|
self.current_view = "Following"
|
||||||
@@ -438,7 +459,7 @@ class OneDriveTUI(App):
|
|||||||
if self.current_view == "Following":
|
if self.current_view == "Following":
|
||||||
self.load_followed_items()
|
self.load_followed_items()
|
||||||
elif self.current_view == "Root":
|
elif self.current_view == "Root":
|
||||||
self.load_root_items()
|
self.load_drive_folder_items()
|
||||||
self.notify("Refreshed items")
|
self.notify("Refreshed items")
|
||||||
|
|
||||||
async def action_toggle_follow(self) -> None:
|
async def action_toggle_follow(self) -> None:
|
||||||
@@ -479,13 +500,15 @@ class OneDriveTUI(App):
|
|||||||
"""Quit the application."""
|
"""Quit the application."""
|
||||||
self.exit()
|
self.exit()
|
||||||
|
|
||||||
async def action_navigate_back(self) -> None:
|
def action_navigate_back(self) -> None:
|
||||||
"""Navigate back to the previous folder."""
|
"""Navigate back to the previous folder."""
|
||||||
if self.folder_history:
|
if self.folder_history:
|
||||||
previous_entry = self.folder_history.pop()
|
previous_entry = self.folder_history.pop()
|
||||||
self.current_folder_id = previous_entry.folder_id
|
self.current_folder_id = previous_entry.folder_id
|
||||||
self.current_folder_name = previous_entry.folder_name
|
self.current_folder_name = previous_entry.folder_name
|
||||||
self.load_root_items(folder_id=previous_entry.folder_id, drive_id=previous_entry.parent_id, track_history=False)
|
if len(self.folder_history) <= 0:
|
||||||
|
self.query_one("#back_button").add_class("hide")
|
||||||
|
self.load_drive_folder_items(folder_id=previous_entry.folder_id, drive_id=previous_entry.parent_id, track_history=False)
|
||||||
else:
|
else:
|
||||||
self.notify("No previous folder to navigate back to")
|
self.notify("No previous folder to navigate back to")
|
||||||
|
|
||||||
|
|||||||
@@ -42,18 +42,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Status and loading elements */
|
/* Status and loading elements */
|
||||||
#status_label {
|
|
||||||
|
#top_bar {
|
||||||
|
height: 4;
|
||||||
|
|
||||||
|
#status_label {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: $accent;
|
color: $accent;
|
||||||
padding:1;
|
padding:1;
|
||||||
|
width: 2fr
|
||||||
|
}
|
||||||
|
|
||||||
|
#view_options {
|
||||||
|
border: round $secondary;
|
||||||
|
width: 1fr;
|
||||||
|
min-width: 40;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#view_options {
|
|
||||||
border: round $secondary;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading_container {
|
#loading_container {
|
||||||
height: 3;
|
height: 3;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -96,11 +104,42 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#items_table {
|
#items_table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File icon styling in the data table */
|
||||||
|
.datatable--cell:first-child {
|
||||||
|
color: $accent;
|
||||||
|
text-align: center;
|
||||||
|
padding-right: 1;
|
||||||
|
min-width: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom icon colors by file type */
|
||||||
|
.folder-icon {
|
||||||
|
color: $warning; /* Folders are yellow/orange */
|
||||||
|
}
|
||||||
|
|
||||||
|
.document-icon {
|
||||||
|
color: $primary; /* Documents are blue */
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-icon {
|
||||||
|
color: $success; /* Images are green */
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-icon {
|
||||||
|
color: $accent-lighten-2; /* Code files are lighter accent color */
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-icon {
|
||||||
|
color: $error; /* Archives are red */
|
||||||
|
}
|
||||||
|
|
||||||
#no_items_label {
|
#no_items_label {
|
||||||
color: $text-muted;
|
color: $text-muted;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -140,6 +179,7 @@
|
|||||||
width: auto;
|
width: auto;
|
||||||
height: 3;
|
height: 3;
|
||||||
align: right middle;
|
align: right middle;
|
||||||
|
margin-right: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#button_container Button {
|
#button_container Button {
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ class EmailViewerApp(App):
|
|||||||
self.fetch_envelopes()
|
self.fetch_envelopes()
|
||||||
|
|
||||||
async def action_archive(self) -> None:
|
async def action_archive(self) -> None:
|
||||||
|
# Remove from all data structures
|
||||||
self.all_envelopes = [item for item in self.all_envelopes if item and item.get("id") != self.current_message_id]
|
self.all_envelopes = [item for item in self.all_envelopes if item and item.get("id") != self.current_message_id]
|
||||||
self.envelope_map.pop(self.current_message_id, None)
|
self.envelope_map.pop(self.current_message_id, None)
|
||||||
self.envelope_index_map = {index: id for index, id in self.envelope_index_map.items() if id != self.current_message_id}
|
self.envelope_index_map = {index: id for index, id in self.envelope_index_map.items() if id != self.current_message_id}
|
||||||
@@ -523,13 +524,30 @@ class EmailViewerApp(App):
|
|||||||
k: v for k, v in self.message_body_cache.items() if k != self.current_message_id
|
k: v for k, v in self.message_body_cache.items() if k != self.current_message_id
|
||||||
}
|
}
|
||||||
self.total_messages = len(self.message_metadata)
|
self.total_messages = len(self.message_metadata)
|
||||||
|
|
||||||
|
# Perform archive operation
|
||||||
worker = archive_current(self)
|
worker = archive_current(self)
|
||||||
await worker.wait()
|
await worker.wait()
|
||||||
newmsg = self.all_envelopes[self.current_message_index]
|
|
||||||
if newmsg.get("type") == "header":
|
# Get next message to display
|
||||||
newmsg = self.all_envelopes[self.current_message_index + 1]
|
try:
|
||||||
return
|
newmsg = self.all_envelopes[self.current_message_index]
|
||||||
self.show_message(newmsg["id"])
|
# Skip headers
|
||||||
|
if newmsg.get("type") == "header":
|
||||||
|
if self.current_message_index + 1 < len(self.all_envelopes):
|
||||||
|
newmsg = self.all_envelopes[self.current_message_index + 1]
|
||||||
|
else:
|
||||||
|
# If we're at the end, go to the previous message
|
||||||
|
newmsg = self.all_envelopes[self.current_message_index - 1]
|
||||||
|
self.current_message_index -= 1
|
||||||
|
|
||||||
|
# Show the next message
|
||||||
|
if "id" in newmsg:
|
||||||
|
self.show_message(newmsg["id"])
|
||||||
|
except (IndexError, KeyError):
|
||||||
|
# If no more messages, just reload envelopes
|
||||||
|
self.reload_needed = True
|
||||||
|
self.fetch_envelopes()
|
||||||
|
|
||||||
def action_open(self) -> None:
|
def action_open(self) -> None:
|
||||||
action_open(self)
|
action_open(self)
|
||||||
|
|||||||
@@ -82,15 +82,15 @@ class DocumentViewerScreen(Screen):
|
|||||||
"""Compose the document viewer screen."""
|
"""Compose the document viewer screen."""
|
||||||
yield Container(
|
yield Container(
|
||||||
Horizontal(
|
Horizontal(
|
||||||
|
Container(
|
||||||
|
Button("✕", id="close_button"),
|
||||||
|
id="button_container"
|
||||||
|
),
|
||||||
Container(
|
Container(
|
||||||
Label(f"Viewing: {self.item_name}", id="document_title"),
|
Label(f"Viewing: {self.item_name}", id="document_title"),
|
||||||
Label(f'[link="{self.web_url}"]Open on Web[/link] | [link="{self.download_url}"]Download File[/link]', id="document_link"),
|
Label(f'[link="{self.web_url}"]Open on Web[/link] | [link="{self.download_url}"]Download File[/link]', id="document_link"),
|
||||||
),
|
),
|
||||||
Container(
|
id="top_container"
|
||||||
Button("Close", id="close_button"),
|
|
||||||
id="button_container"
|
|
||||||
),
|
|
||||||
id="top_container"
|
|
||||||
),
|
),
|
||||||
ScrollableContainer(
|
ScrollableContainer(
|
||||||
Markdown("", id="markdown_content"),
|
Markdown("", id="markdown_content"),
|
||||||
|
|||||||
123
utils/file_icons.py
Normal file
123
utils/file_icons.py
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
def get_file_icon(name, is_folder, with_color=False):
|
||||||
|
"""Return a Nerd Font glyph based on file type or extension, optionally with color markup."""
|
||||||
|
icon = ""
|
||||||
|
color = ""
|
||||||
|
|
||||||
|
if is_folder:
|
||||||
|
icon = "\uf07b" # Nerd Font folder icon
|
||||||
|
color = "#FFB86C" # Folder color (orange/yellow)
|
||||||
|
else:
|
||||||
|
# Get the file extension
|
||||||
|
_, ext = os.path.splitext(name.lower())
|
||||||
|
|
||||||
|
# Map extensions to icons and colors
|
||||||
|
icons = {
|
||||||
|
# Documents
|
||||||
|
".pdf": ("\uf1c1", "#8BE9FD"), # PDF - cyan
|
||||||
|
".doc": ("\uf1c2", "#8BE9FD"), ".docx": ("\uf1c2", "#8BE9FD"), # Word - cyan
|
||||||
|
".xls": ("\uf1c3", "#8BE9FD"), ".xlsx": ("\uf1c3", "#8BE9FD"), # Excel - cyan
|
||||||
|
".ppt": ("\uf1c4", "#8BE9FD"), ".pptx": ("\uf1c4", "#8BE9FD"), # PowerPoint - cyan
|
||||||
|
".txt": ("\uf15c", "#8BE9FD"), # Text - cyan
|
||||||
|
".md": ("\uf48a", "#8BE9FD"), # Markdown - cyan
|
||||||
|
".rtf": ("\uf15c", "#8BE9FD"), # RTF - cyan
|
||||||
|
".odt": ("\uf1c2", "#8BE9FD"), # ODT - cyan
|
||||||
|
|
||||||
|
# Code/Development
|
||||||
|
".py": ("\ue73c", "#BD93F9"), # Python - purple
|
||||||
|
".js": ("\ue781", "#BD93F9"), # JavaScript - purple
|
||||||
|
".ts": ("\ue628", "#BD93F9"), # TypeScript - purple
|
||||||
|
".html": ("\uf13b", "#BD93F9"), ".htm": ("\uf13b", "#BD93F9"), # HTML - purple
|
||||||
|
".css": ("\uf13c", "#BD93F9"), # CSS - purple
|
||||||
|
".json": ("\ue60b", "#BD93F9"), # JSON - purple
|
||||||
|
".xml": ("\uf121", "#BD93F9"), # XML - purple
|
||||||
|
".yml": ("\uf481", "#BD93F9"), ".yaml": ("\uf481", "#BD93F9"), # YAML - purple
|
||||||
|
".sh": ("\uf489", "#BD93F9"), # Shell script - purple
|
||||||
|
".bat": ("\uf489", "#BD93F9"), # Batch - purple
|
||||||
|
".ps1": ("\uf489", "#BD93F9"), # PowerShell - purple
|
||||||
|
".cpp": ("\ue61d", "#BD93F9"), ".c": ("\ue61e", "#BD93F9"), # C/C++ - purple
|
||||||
|
".java": ("\ue738", "#BD93F9"), # Java - purple
|
||||||
|
".rb": ("\ue739", "#BD93F9"), # Ruby - purple
|
||||||
|
".go": ("\ue724", "#BD93F9"), # Go - purple
|
||||||
|
".php": ("\ue73d", "#BD93F9"), # PHP - purple
|
||||||
|
|
||||||
|
# Images
|
||||||
|
".jpg": ("\uf1c5", "#50FA7B"), ".jpeg": ("\uf1c5", "#50FA7B"), # JPEG - green
|
||||||
|
".png": ("\uf1c5", "#50FA7B"), # PNG - green
|
||||||
|
".gif": ("\uf1c5", "#50FA7B"), # GIF - green
|
||||||
|
".svg": ("\uf1c5", "#50FA7B"), # SVG - green
|
||||||
|
".bmp": ("\uf1c5", "#50FA7B"), # BMP - green
|
||||||
|
".tiff": ("\uf1c5", "#50FA7B"), ".tif": ("\uf1c5", "#50FA7B"), # TIFF - green
|
||||||
|
".ico": ("\uf1c5", "#50FA7B"), # ICO - green
|
||||||
|
|
||||||
|
# Media
|
||||||
|
".mp3": ("\uf1c7", "#FF79C6"), # Audio - pink
|
||||||
|
".wav": ("\uf1c7", "#FF79C6"), # Audio - pink
|
||||||
|
".ogg": ("\uf1c7", "#FF79C6"), # Audio - pink
|
||||||
|
".mp4": ("\uf1c8", "#FF79C6"), # Video - pink
|
||||||
|
".avi": ("\uf1c8", "#FF79C6"), # Video - pink
|
||||||
|
".mov": ("\uf1c8", "#FF79C6"), # Video - pink
|
||||||
|
".mkv": ("\uf1c8", "#FF79C6"), # Video - pink
|
||||||
|
".wmv": ("\uf1c8", "#FF79C6"), # Video - pink
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
".zip": ("\uf1c6", "#FF5555"), # ZIP - red
|
||||||
|
".rar": ("\uf1c6", "#FF5555"), # RAR - red
|
||||||
|
".7z": ("\uf1c6", "#FF5555"), # 7z - red
|
||||||
|
".tar": ("\uf1c6", "#FF5555"), ".gz": ("\uf1c6", "#FF5555"), # TAR/GZ - red
|
||||||
|
".bz2": ("\uf1c6", "#FF5555"), # BZ2 - red
|
||||||
|
|
||||||
|
# Others
|
||||||
|
".exe": ("\uf085", "#F8F8F2"), # Executable - white
|
||||||
|
".iso": ("\uf0a0", "#F8F8F2"), # ISO - white
|
||||||
|
".dll": ("\uf085", "#F8F8F2"), # DLL - white
|
||||||
|
".db": ("\uf1c0", "#F8F8F2"), # Database - white
|
||||||
|
".sql": ("\uf1c0", "#F8F8F2"), # SQL - white
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set default icon and color for unknown file types
|
||||||
|
icon = "\uf15b" # Default file icon
|
||||||
|
color = "#F8F8F2" # Default color (white)
|
||||||
|
|
||||||
|
# Get icon and color from the map if the extension exists
|
||||||
|
if ext in icons:
|
||||||
|
icon, color = icons[ext]
|
||||||
|
|
||||||
|
# Return either plain icon or with color markup
|
||||||
|
if with_color:
|
||||||
|
return f"[{color}]{icon}[/]"
|
||||||
|
else:
|
||||||
|
return icon
|
||||||
|
|
||||||
|
def get_icon_class(name, is_folder):
|
||||||
|
"""Determine CSS class for the icon based on file type."""
|
||||||
|
if is_folder:
|
||||||
|
return "folder-icon"
|
||||||
|
|
||||||
|
# Get the file extension
|
||||||
|
_, ext = os.path.splitext(name.lower())
|
||||||
|
|
||||||
|
# Document files
|
||||||
|
if ext in [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".md", ".rtf", ".odt"]:
|
||||||
|
return "document-icon"
|
||||||
|
|
||||||
|
# Code files
|
||||||
|
elif ext in [".py", ".js", ".ts", ".html", ".htm", ".css", ".json", ".xml", ".yml", ".yaml",
|
||||||
|
".sh", ".bat", ".ps1", ".cpp", ".c", ".java", ".rb", ".go", ".php"]:
|
||||||
|
return "code-icon"
|
||||||
|
|
||||||
|
# Image files
|
||||||
|
elif ext in [".jpg", ".jpeg", ".png", ".gif", ".svg", ".bmp", ".tiff", ".tif", ".ico"]:
|
||||||
|
return "image-icon"
|
||||||
|
|
||||||
|
# Archive files
|
||||||
|
elif ext in [".zip", ".rar", ".7z", ".tar", ".gz", ".bz2"]:
|
||||||
|
return "archive-icon"
|
||||||
|
|
||||||
|
# Media files
|
||||||
|
elif ext in [".mp3", ".wav", ".ogg", ".mp4", ".avi", ".mov", ".mkv", ".wmv"]:
|
||||||
|
return "media-icon"
|
||||||
|
|
||||||
|
# Default for other file types
|
||||||
|
return ""
|
||||||
Reference in New Issue
Block a user