Files
finance/src/components/Sidebar.astro

207 lines
5.4 KiB
Plaintext

---
import type { Account } from "@types";
import AddTransactionForm from "./AddTransactionForm";
import AccountSummary from "./AccountSummary";
interface Props {
accounts: Account[];
initialAccount: Account;
}
const { accounts, initialAccount } = Astro.props;
---
<aside class="sidebar">
<div class="sidebar-header">
<h2>My finances</h2>
</div>
<nav class="account-nav">
<h3>Accounts</h3>
<select id="account-select" name="account" class="form-input">
{
accounts.map((account) => (
<option
value={account.id}
selected={account.id === initialAccount.id}
>
{account.name} (***{account.accountNumber.slice(-3)})
</option>
))
}
</select>
</nav>
<!-- Add Transaction Section with Toggle - Moved up to be right after account dropdown -->
<section id="add-transaction-section" class="add-transaction-section">
<button
type="button"
class="toggle-form-btn"
id="toggle-add-txn-btn"
aria-controls="add-transaction-form"
aria-expanded="false"
>
Add Transaction
</button>
<div id="add-transaction-form" class="collapsible-form collapsed">
<AddTransactionForm client:load />
</div>
</section>
<!-- Account Summary Section - Always visible -->
<div class="account-summary-section" id="account-summary-section">
<AccountSummary client:load />
</div>
</aside>
<!-- Toggle button for sidebar on mobile -->
<button
type="button"
class="sidebar-toggle"
id="sidebar-toggle"
aria-controls="sidebar-content"
aria-expanded="true"
>
<span>Toggle sidebar</span>
<span class="sidebar-toggle-icon">▲</span>
</button>
<script>
// Add Transaction form toggle
const toggleAddTxnBtn = document.getElementById("toggle-add-txn-btn");
const addTransactionForm = document.getElementById("add-transaction-form");
toggleAddTxnBtn?.addEventListener("click", () => {
const isExpanded =
toggleAddTxnBtn.getAttribute("aria-expanded") === "true";
toggleAddTxnBtn.setAttribute(
"aria-expanded",
isExpanded ? "false" : "true",
);
if (isExpanded) {
addTransactionForm?.classList.add("collapsed");
} else {
addTransactionForm?.classList.remove("collapsed");
}
});
// Sidebar toggle for mobile
const sidebarToggleBtn = document.getElementById("sidebar-toggle");
const sidebar = document.querySelector(".sidebar");
sidebarToggleBtn?.addEventListener("click", () => {
const isExpanded =
sidebarToggleBtn.getAttribute("aria-expanded") === "true";
sidebarToggleBtn.setAttribute(
"aria-expanded",
isExpanded ? "false" : "true",
);
if (isExpanded) {
sidebar?.classList.add("sidebar-collapsed");
} else {
sidebar?.classList.remove("sidebar-collapsed");
}
});
// Check if we're on mobile and collapse sidebar by default
const checkMobile = () => {
const isMobile = window.innerWidth < 1024;
if (isMobile && sidebar && sidebarToggleBtn) {
// Start with sidebar collapsed on mobile
sidebar.classList.add("sidebar-collapsed");
sidebarToggleBtn.setAttribute("aria-expanded", "false");
} else if (sidebar && sidebarToggleBtn) {
sidebar.classList.remove("sidebar-collapsed");
sidebarToggleBtn.setAttribute("aria-expanded", "true");
}
};
// Check on load and window resize
window.addEventListener("load", checkMobile);
window.addEventListener("resize", checkMobile);
</script>
<style>
.sidebar {
padding: 20px;
background-color: #f9fafb;
border-right: 1px solid #e5e7eb;
height: 100%;
overflow-y: auto;
}
.sidebar-collapsed {
display: none;
}
.sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
}
.account-nav {
margin-bottom: 15px;
}
.account-nav h3 {
margin-bottom: 8px;
font-size: 16px;
}
/* Ensure account summary is always visible */
.account-summary-section {
margin-bottom: 15px;
padding-bottom: 5px;
}
.add-transaction-section {
margin-bottom: 15px;
}
.add-transaction-section .toggle-form-btn {
display: block;
width: 100%;
margin-bottom: 0;
}
.collapsible-form.collapsed {
display: none;
}
.sidebar-toggle {
display: none;
position: fixed;
bottom: 20px;
right: 20px;
background-color: #f9fafb;
border: 1px solid #e5e7eb;
padding: 10px;
cursor: pointer;
z-index: 100;
width: auto;
min-width: 140px;
text-align: center;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
border-radius: 4px;
}
.sidebar-toggle span {
pointer-events: none;
}
.sidebar-toggle-icon {
margin-left: 8px;
pointer-events: none;
}
@media (max-width: 1024px) {
.sidebar-toggle {
display: block;
}
}
</style>