mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 13:19:39 +02:00
Maybe Design System Updates (#1856)
* Add geist font * Design system css file * Add cursor ui/ux rules * Add shadows and shadow borders * Replace primitives with tokens for common text and backgrounds * Organize css * Update switch and checkbox class names * Add back global color variables
This commit is contained in:
parent
c0e290a07e
commit
849c58dd3e
193 changed files with 1356 additions and 1073 deletions
13
.cursor/rules/ui-ux-design-guidelines.mdc
Normal file
13
.cursor/rules/ui-ux-design-guidelines.mdc
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
description: This file describes Maybe's design system and how views should be styled
|
||||
globs: app/views/**,app/helpers/**,app/javascript/controllers/**
|
||||
---
|
||||
Use this rule whenever you are writing html, css, or even styles in Stimulus controllers that use D3.js.
|
||||
|
||||
The codebase uses TailwindCSS v4.x (the newest version) with a custom design system defined in [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css)
|
||||
|
||||
- Always start by referencing [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css) to see the base primitives and tokens we use in the codebase
|
||||
- Always generate semantic HTML
|
||||
- Never create new styles in [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css) or [application.css](mdc:app/assets/tailwind/application.css) without explicitly receiving permission to do so
|
||||
- Always favor the "utility first" Tailwind approach. Reusable style classes should not be created often. Code should be reused primarily through ERB partials.
|
||||
- Always prefer using the utility "tokens" defined in [maybe-design-system.css](mdc:app/assets/tailwind/maybe-design-system.css) when possible. For example, use `text-primary` rather than `text-gray-900`.
|
BIN
app/assets/fonts/geist/Geist-Black.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-Black.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-Bold.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-Bold.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-ExtraBold.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-ExtraBold.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-ExtraLight.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-ExtraLight.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-Light.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-Light.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-Medium.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-Medium.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-Regular.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-Regular.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-SemiBold.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-SemiBold.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist-Thin.woff2
Normal file
BIN
app/assets/fonts/geist/Geist-Thin.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist/Geist[wght].woff2
Normal file
BIN
app/assets/fonts/geist/Geist[wght].woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-Black.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-Black.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-Bold.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-Bold.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-Light.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-Light.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-Medium.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-Medium.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-Regular.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-Regular.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-SemiBold.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-SemiBold.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-Thin.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-Thin.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-UltraBlack.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-UltraBlack.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono-UltraLight.woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono-UltraLight.woff2
Normal file
Binary file not shown.
BIN
app/assets/fonts/geist_mono/GeistMono[wght].woff2
Normal file
BIN
app/assets/fonts/geist_mono/GeistMono[wght].woff2
Normal file
Binary file not shown.
|
@ -1,389 +1,13 @@
|
|||
@import 'tailwindcss';
|
||||
|
||||
@import "./maybe-design-system.css";
|
||||
|
||||
@import "./geist-font.css";
|
||||
@import "./geist-mono-font.css";
|
||||
|
||||
@plugin "@tailwindcss/typography";
|
||||
@plugin "@tailwindcss/forms";
|
||||
|
||||
@theme {
|
||||
/* Base colors */
|
||||
--color-white: #ffffff;
|
||||
--color-black: #0B0B0B;
|
||||
--color-success: #10A861;
|
||||
--color-warning: #F79009;
|
||||
--color-error: #F13636;
|
||||
|
||||
/* Gray scale */
|
||||
--color-gray-25: #FAFAFA;
|
||||
--color-gray-50: #F5F5F5;
|
||||
--color-gray-100: #F0F0F0;
|
||||
--color-gray-200: #E5E5E5;
|
||||
--color-gray-300: #D6D6D6;
|
||||
--color-gray-400: #A3A3A3;
|
||||
--color-gray-500: #737373;
|
||||
--color-gray-600: #525252;
|
||||
--color-gray-700: #3D3D3D;
|
||||
--color-gray-800: #212121;
|
||||
--color-gray-900: #141414;
|
||||
|
||||
/* Alpha colors */
|
||||
--color-alpha-white-25: rgba(255, 255, 255, 0.03);
|
||||
--color-alpha-white-50: rgba(255, 255, 255, 0.05);
|
||||
--color-alpha-white-100: rgba(255, 255, 255, 0.08);
|
||||
--color-alpha-white-200: rgba(255, 255, 255, 0.1);
|
||||
--color-alpha-white-300: rgba(255, 255, 255, 0.15);
|
||||
--color-alpha-white-400: rgba(255, 255, 255, 0.2);
|
||||
--color-alpha-white-500: rgba(255, 255, 255, 0.3);
|
||||
--color-alpha-white-600: rgba(255, 255, 255, 0.4);
|
||||
--color-alpha-white-700: rgba(255, 255, 255, 0.5);
|
||||
--color-alpha-white-800: rgba(255, 255, 255, 0.6);
|
||||
--color-alpha-white-900: rgba(255, 255, 255, 0.7);
|
||||
|
||||
--color-alpha-black-25: rgba(11, 11, 11, 0.03);
|
||||
--color-alpha-black-50: rgba(11, 11, 11, 0.05);
|
||||
--color-alpha-black-100: rgba(11, 11, 11, 0.08);
|
||||
--color-alpha-black-200: rgba(11, 11, 11, 0.1);
|
||||
--color-alpha-black-300: rgba(11, 11, 11, 0.15);
|
||||
--color-alpha-black-400: rgba(11, 11, 11, 0.2);
|
||||
--color-alpha-black-500: rgba(11, 11, 11, 0.3);
|
||||
--color-alpha-black-600: rgba(11, 11, 11, 0.4);
|
||||
--color-alpha-black-700: rgba(11, 11, 11, 0.5);
|
||||
--color-alpha-black-800: rgba(11, 11, 11, 0.6);
|
||||
--color-alpha-black-900: rgba(11, 11, 11, 0.7);
|
||||
|
||||
/* Red scale */
|
||||
--color-red-25: #FFFBFB;
|
||||
--color-red-50: #FFF1F0;
|
||||
--color-red-100: #FFDEDB;
|
||||
--color-red-200: #FEB9B3;
|
||||
--color-red-300: #F88C86;
|
||||
--color-red-400: #ED4E4E;
|
||||
--color-red-500: #F13636;
|
||||
--color-red-600: #EC2222;
|
||||
--color-red-700: #C91313;
|
||||
--color-red-800: #A40E0E;
|
||||
--color-red-900: #7E0707;
|
||||
|
||||
/* Green scale */
|
||||
--color-green-25: #F6FEF9;
|
||||
--color-green-50: #ECFDF3;
|
||||
--color-green-100: #D1FADF;
|
||||
--color-green-200: #A6F4C5;
|
||||
--color-green-300: #6CE9A6;
|
||||
--color-green-400: #32D583;
|
||||
--color-green-500: #12B76A;
|
||||
--color-green-600: #10A861;
|
||||
--color-green-700: #078C52;
|
||||
--color-green-800: #05603A;
|
||||
--color-green-900: #054F31;
|
||||
|
||||
/* Yellow scale */
|
||||
--color-yellow-25: #FFFCF5;
|
||||
--color-yellow-50: #FFFAEB;
|
||||
--color-yellow-100: #FEF0C7;
|
||||
--color-yellow-200: #FEDF89;
|
||||
--color-yellow-300: #FEC84B;
|
||||
--color-yellow-400: #FDB022;
|
||||
--color-yellow-500: #F79009;
|
||||
--color-yellow-600: #DC6803;
|
||||
--color-yellow-700: #B54708;
|
||||
--color-yellow-800: #93370D;
|
||||
--color-yellow-900: #7A2E0E;
|
||||
|
||||
/* Cyan scale */
|
||||
--color-cyan-25: #F5FEFF;
|
||||
--color-cyan-50: #ECFDFF;
|
||||
--color-cyan-100: #CFF9FE;
|
||||
--color-cyan-200: #A5F0FC;
|
||||
--color-cyan-300: #67E3F9;
|
||||
--color-cyan-400: #22CCEE;
|
||||
--color-cyan-500: #06AED4;
|
||||
--color-cyan-600: #088AB2;
|
||||
--color-cyan-700: #0E7090;
|
||||
--color-cyan-800: #155B75;
|
||||
--color-cyan-900: #155B75;
|
||||
|
||||
/* Blue scale */
|
||||
--color-blue-25: #F5FAFF;
|
||||
--color-blue-50: #EFF8FF;
|
||||
--color-blue-100: #D1E9FF;
|
||||
--color-blue-200: #B2DDFF;
|
||||
--color-blue-300: #84CAFF;
|
||||
--color-blue-400: #53B1FD;
|
||||
--color-blue-500: #2E90FA;
|
||||
--color-blue-600: #1570EF;
|
||||
--color-blue-700: #175CD3;
|
||||
--color-blue-800: #1849A9;
|
||||
--color-blue-900: #194185;
|
||||
|
||||
/* Indigo scale */
|
||||
--color-indigo-25: #F5F8FF;
|
||||
--color-indigo-50: #EFF4FF;
|
||||
--color-indigo-100: #E0EAFF;
|
||||
--color-indigo-200: #C7D7FE;
|
||||
--color-indigo-300: #A4BCFD;
|
||||
--color-indigo-400: #8098F9;
|
||||
--color-indigo-500: #6172F3;
|
||||
--color-indigo-600: #444CE7;
|
||||
--color-indigo-700: #3538CD;
|
||||
--color-indigo-800: #2D31A6;
|
||||
--color-indigo-900: #2D3282;
|
||||
|
||||
/* Violet scale */
|
||||
--color-violet-25: #FBFAFF;
|
||||
--color-violet-50: #F5F3FF;
|
||||
--color-violet-100: #ECE9FE;
|
||||
--color-violet-200: #DDD6FE;
|
||||
--color-violet-300: #C3B5FD;
|
||||
--color-violet-400: #A48AFB;
|
||||
--color-violet-500: #875BF7;
|
||||
--color-violet-600: #7839EE;
|
||||
--color-violet-700: #6927DA;
|
||||
|
||||
/* Fuchsia scale */
|
||||
--color-fuchsia-25: #FEFAFF;
|
||||
--color-fuchsia-50: #FDF4FF;
|
||||
--color-fuchsia-100: #FBE8FF;
|
||||
--color-fuchsia-200: #F6D0FE;
|
||||
--color-fuchsia-300: #EEAAFD;
|
||||
--color-fuchsia-400: #E478FA;
|
||||
--color-fuchsia-500: #D444F1;
|
||||
--color-fuchsia-600: #BA24D5;
|
||||
--color-fuchsia-700: #9F1AB1;
|
||||
--color-fuchsia-800: #821890;
|
||||
--color-fuchsia-900: #6F1877;
|
||||
|
||||
/* Pink scale */
|
||||
--color-pink-25: #FFFAFC;
|
||||
--color-pink-50: #FEF0F7;
|
||||
--color-pink-100: #FFD1E2;
|
||||
--color-pink-200: #FFB1CE;
|
||||
--color-pink-300: #FD8FBA;
|
||||
--color-pink-400: #F86BA7;
|
||||
--color-pink-500: #F23E94;
|
||||
--color-pink-600: #D5327F;
|
||||
--color-pink-700: #BA256B;
|
||||
--color-pink-800: #9E1958;
|
||||
--color-pink-900: #840B45;
|
||||
|
||||
/* Orange scale */
|
||||
--color-orange-25: #FFF9F5;
|
||||
--color-orange-50: #FFF4ED;
|
||||
--color-orange-100: #FFE6D5;
|
||||
--color-orange-200: #FFD6AE;
|
||||
--color-orange-300: #FF9C66;
|
||||
--color-orange-400: #FF692E;
|
||||
--color-orange-500: #FF4405;
|
||||
--color-orange-600: #E62E05;
|
||||
--color-orange-700: #BC1B06;
|
||||
--color-orange-800: #97180C;
|
||||
--color-orange-900: #771A0D;
|
||||
|
||||
/* Shadows */
|
||||
--shadow-none: 0 0 #0000;
|
||||
--shadow-xs: 0px 1px 2px 0px rgba(11, 11, 11, 0.05);
|
||||
--shadow-sm: 0px 1px 2px 0px rgba(11, 11, 11, 0.06), 0px 1px 3px 0px rgba(11, 11, 11, 0.10);
|
||||
--shadow-md: 0px 2px 4px -2px rgba(11, 11, 11, 0.06), 0px 4px 8px -2px rgba(11, 11, 11, 0.10);
|
||||
--shadow-lg: 0px 4px 6px -2px rgba(11, 11, 11, 0.03), 0px 12px 16px -4px rgba(11, 11, 11, 0.08);
|
||||
--shadow-xl: 0px 8px 8px -4px rgba(11, 11, 11, 0.03), 0px 20px 24px -4px rgba(11, 11, 11, 0.08);
|
||||
--shadow-2xl: 0px 24px 48px -12px rgba(11, 11, 11, 0.12);
|
||||
--shadow-3xl: 0px 32px 64px -12px rgba(11, 11, 11, 0.14);
|
||||
|
||||
/* Border radius */
|
||||
--border-radius-none: 0;
|
||||
--border-radius-full: 9999px;
|
||||
--border-radius-xs: 2px;
|
||||
--border-radius-sm: 4px;
|
||||
--border-radius-md: 8px;
|
||||
--border-radius-lg: 10px;
|
||||
--border-radius-xl: 12px;
|
||||
--border-radius-2xl: 16px;
|
||||
--border-radius-3xl: 24px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
@apply flex flex-col gap-1 relative px-3 py-2 rounded-md border bg-white border-alpha-black-100 shadow-xs w-full;
|
||||
@apply focus-within:border-gray-900 focus-within:shadow-none focus-within:ring-4 focus-within:ring-gray-100;
|
||||
}
|
||||
|
||||
.form-field__label {
|
||||
@apply block text-xs text-gray-500 peer-disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.hw-combobox__label {
|
||||
@apply block text-xs text-gray-500 peer-disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.form-field__input {
|
||||
@apply border-none bg-transparent text-sm opacity-100 w-full p-0;
|
||||
@apply focus:opacity-100 focus:outline-hidden focus:ring-0;
|
||||
@apply placeholder-shown:opacity-50;
|
||||
@apply disabled:text-gray-400;
|
||||
@apply text-ellipsis overflow-hidden whitespace-nowrap;
|
||||
|
||||
&select {
|
||||
@apply pr-8;
|
||||
}
|
||||
}
|
||||
|
||||
.form-field__radio {
|
||||
@apply text-gray-900;
|
||||
}
|
||||
|
||||
.form-field__submit {
|
||||
@apply cursor-pointer rounded-lg bg-black p-3 text-center text-white hover:bg-gray-700;
|
||||
}
|
||||
|
||||
.toggle-switch-dot {
|
||||
input:checked + label + & {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
.maybe-checkbox {
|
||||
&[type='checkbox'] {
|
||||
@apply rounded-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.maybe-checkbox--light {
|
||||
&[type='checkbox'] {
|
||||
@apply border-alpha-black-200 checked:bg-gray-900 checked:ring-gray-900 focus:ring-gray-900 focus-visible:ring-gray-900 checked:hover:bg-gray-500;
|
||||
}
|
||||
|
||||
&[type='checkbox']:disabled {
|
||||
@apply cursor-not-allowed opacity-80 bg-gray-50 border-gray-200 checked:bg-gray-400 checked:ring-gray-400;
|
||||
}
|
||||
}
|
||||
|
||||
.maybe-checkbox--dark {
|
||||
&[type='checkbox'] {
|
||||
@apply ring-gray-900 checked:text-white;
|
||||
}
|
||||
|
||||
&[type='checkbox']:disabled {
|
||||
@apply cursor-not-allowed opacity-80 ring-gray-600;
|
||||
}
|
||||
|
||||
&[type='checkbox']:checked {
|
||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='111827' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
|
||||
}
|
||||
}
|
||||
|
||||
.maybe-switch {
|
||||
@apply block bg-gray-100 w-9 h-5 rounded-full cursor-pointer;
|
||||
@apply after:content-[''] after:block after:absolute after:top-0.5 after:left-0.5 after:bg-white after:w-4 after:h-4 after:rounded-full after:transition-transform after:duration-300 after:ease-in-out;
|
||||
@apply peer-checked:bg-green-600 peer-checked:after:translate-x-4;
|
||||
}
|
||||
|
||||
.prose {
|
||||
@apply max-w-none;
|
||||
|
||||
h2 {
|
||||
@apply text-xl font-medium;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-lg font-medium;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply m-0;
|
||||
}
|
||||
|
||||
details {
|
||||
@apply mb-4 rounded-xl mt-3.5;
|
||||
}
|
||||
|
||||
summary {
|
||||
@apply flex items-center gap-1;
|
||||
}
|
||||
|
||||
video {
|
||||
@apply m-0 rounded-b-xl;
|
||||
}
|
||||
}
|
||||
|
||||
.prose--github-release-notes {
|
||||
.octicon {
|
||||
@apply inline-block overflow-visible align-text-bottom fill-current;
|
||||
}
|
||||
|
||||
.dropdown-caret {
|
||||
@apply content-none border-4 border-b-0 border-transparent border-t-gray-500 size-0 inline-block;
|
||||
}
|
||||
|
||||
.user-mention {
|
||||
@apply font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
@apply hidden absolute;
|
||||
}
|
||||
|
||||
.btn {
|
||||
@apply px-3 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:cursor-not-allowed focus:outline-gray-500;
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
@apply bg-gray-900 text-white hover:bg-gray-700 disabled:bg-gray-50 disabled:hover:bg-gray-50 disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.btn--secondary {
|
||||
@apply bg-gray-50 hover:bg-gray-100 text-gray-900;
|
||||
}
|
||||
|
||||
.btn--outline {
|
||||
@apply border border-alpha-black-200 text-gray-900 hover:bg-gray-50 disabled:bg-gray-50 disabled:hover:bg-gray-50 disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.btn--ghost {
|
||||
@apply border border-transparent text-gray-900 hover:bg-gray-50;
|
||||
}
|
||||
.scrollbar {
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #d6d6d6;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: #a6a6a6;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset rules, default styles applied to plain HTML */
|
||||
@layer base {
|
||||
details>summary::-webkit-details-marker {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
details>summary {
|
||||
@apply list-none;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
select[multiple="multiple"] {
|
||||
@apply py-2 pr-2 space-y-0.5 overflow-y-auto;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] option {
|
||||
@apply py-2 rounded-md;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] option:checked {
|
||||
@apply after:content-['\2713'] bg-white after:text-gray-500 after:ml-2;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] option:active,
|
||||
select[multiple="multiple"] option:focus {
|
||||
@apply bg-white;
|
||||
}
|
||||
}
|
||||
|
||||
@utility combobox {
|
||||
.hw-combobox__main__wrapper,
|
||||
.hw-combobox__input {
|
||||
|
@ -398,6 +22,10 @@
|
|||
@apply absolute top-[160%] right-0 w-full bg-transparent rounded z-30;
|
||||
}
|
||||
|
||||
.hw-combobox__label {
|
||||
@apply block text-xs text-gray-500 peer-disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.hw_combobox__pagination__wrapper {
|
||||
@apply h-px;
|
||||
|
||||
|
@ -412,6 +40,20 @@
|
|||
--hw-handle-offset-right: 0px;
|
||||
}
|
||||
|
||||
.prose--github-release-notes {
|
||||
.octicon {
|
||||
@apply inline-block overflow-visible align-text-bottom fill-current;
|
||||
}
|
||||
|
||||
.dropdown-caret {
|
||||
@apply content-none border-4 border-b-0 border-transparent border-t-gray-500 size-0 inline-block;
|
||||
}
|
||||
|
||||
.user-mention {
|
||||
@apply font-bold;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom scrollbar implementation for Windows browsers */
|
||||
.windows {
|
||||
::-webkit-scrollbar {
|
||||
|
@ -427,3 +69,18 @@
|
|||
background: #a6a6a6;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollbar {
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #d6d6d6;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: #a6a6a6;
|
||||
}
|
||||
}
|
83
app/assets/tailwind/geist-font.css
Normal file
83
app/assets/tailwind/geist-font.css
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Variable font */
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist[wght].woff2') format('woff2-variations');
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Static fonts (fallback) */
|
||||
@supports not (font-variation-settings: normal) {
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-Thin.woff2') format('woff2');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-ExtraLight.woff2') format('woff2');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-Light.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-Regular.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-Medium.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-SemiBold.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-Bold.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-ExtraBold.woff2') format('woff2');
|
||||
font-weight: 800;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist';
|
||||
src: url('../fonts/geist/Geist-Black.woff2') format('woff2');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
}
|
83
app/assets/tailwind/geist-mono-font.css
Normal file
83
app/assets/tailwind/geist-mono-font.css
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* Variable font */
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono[wght].woff2') format('woff2-variations');
|
||||
font-weight: 100 950;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Static fonts (fallback) */
|
||||
@supports not (font-variation-settings: normal) {
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-Thin.woff2') format('woff2');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-UltraLight.woff2') format('woff2');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-Light.woff2') format('woff2');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-Regular.woff2') format('woff2');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-Medium.woff2') format('woff2');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-SemiBold.woff2') format('woff2');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-Bold.woff2') format('woff2');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-Black.woff2') format('woff2');
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Geist Mono';
|
||||
src: url('../fonts/geist_mono/GeistMono-UltraBlack.woff2') format('woff2');
|
||||
font-weight: 950;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
}
|
448
app/assets/tailwind/maybe-design-system.css
Normal file
448
app/assets/tailwind/maybe-design-system.css
Normal file
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
This file contains all of the Figma design tokens, components, etc. that
|
||||
are used globally across the app.
|
||||
|
||||
One-off styling (3rd party overrides, etc.) should be done in the application.css file.
|
||||
*/
|
||||
|
||||
@theme {
|
||||
/* Font families */
|
||||
--font-sans: 'Geist', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
|
||||
/* Base colors */
|
||||
--color-white: #ffffff;
|
||||
--color-black: #0B0B0B;
|
||||
--color-success: var(--color-green-600);
|
||||
--color-warning: var(--color-yellow-600);
|
||||
--color-destructive: var(--color-red-600);
|
||||
|
||||
/* Gray scale */
|
||||
--color-gray-25: #FAFAFA;
|
||||
--color-gray-50: #F7F7F7;
|
||||
--color-gray-100: #F0F0F0;
|
||||
--color-gray-200: #E7E7E7;
|
||||
--color-gray-300: #CFCFCF;
|
||||
--color-gray-400: #9E9E9E;
|
||||
--color-gray-500: #737373;
|
||||
--color-gray-600: #5C5C5C;
|
||||
--color-gray-700: #363636;
|
||||
--color-gray-800: #242424;
|
||||
--color-gray-900: #171717;
|
||||
--color-gray: var(--color-gray-500);
|
||||
--color-gray-tint-5: --alpha(var(--color-gray-500) / 5%);
|
||||
--color-gray-tint-10: --alpha(var(--color-gray-500) / 10%);
|
||||
|
||||
/* Alpha colors */
|
||||
--color-alpha-white-25: --alpha(var(--color-white) / 3%);
|
||||
--color-alpha-white-50: --alpha(var(--color-white) / 5%);
|
||||
--color-alpha-white-100: --alpha(var(--color-white) / 8%);
|
||||
--color-alpha-white-200: --alpha(var(--color-white) / 10%);
|
||||
--color-alpha-white-300: --alpha(var(--color-white) / 15%);
|
||||
--color-alpha-white-400: --alpha(var(--color-white) / 20%);
|
||||
--color-alpha-white-500: --alpha(var(--color-white) / 30%);
|
||||
--color-alpha-white-600: --alpha(var(--color-white) / 40%);
|
||||
--color-alpha-white-700: --alpha(var(--color-white) / 50%);
|
||||
--color-alpha-white-800: --alpha(var(--color-white) / 70%);
|
||||
--color-alpha-white-900: --alpha(var(--color-white) / 85%);
|
||||
|
||||
--color-alpha-black-25: --alpha(var(--color-black) / 3%);
|
||||
--color-alpha-black-50: --alpha(var(--color-black) / 5%);
|
||||
--color-alpha-black-100: --alpha(var(--color-black) / 8%);
|
||||
--color-alpha-black-200: --alpha(var(--color-black) / 10%);
|
||||
--color-alpha-black-300: --alpha(var(--color-black) / 15%);
|
||||
--color-alpha-black-400: --alpha(var(--color-black) / 20%);
|
||||
--color-alpha-black-500: --alpha(var(--color-black) / 30%);
|
||||
--color-alpha-black-600: --alpha(var(--color-black) / 40%);
|
||||
--color-alpha-black-700: --alpha(var(--color-black) / 50%);
|
||||
--color-alpha-black-800: --alpha(var(--color-black) / 70%);
|
||||
--color-alpha-black-900: --alpha(var(--color-black) / 85%);
|
||||
|
||||
/* Red scale */
|
||||
--color-red-25: #FFFBFB;
|
||||
--color-red-50: #FFF1F0;
|
||||
--color-red-100: #FFDEDB;
|
||||
--color-red-200: #FEB9B3;
|
||||
--color-red-300: #F88C86;
|
||||
--color-red-400: #ED4E4E;
|
||||
--color-red-500: #F13636;
|
||||
--color-red-600: #EC2222;
|
||||
--color-red-700: #C91313;
|
||||
--color-red-800: #A40E0E;
|
||||
--color-red-900: #7E0707;
|
||||
--color-red-tint-5: --alpha(var(--color-red-500) / 5%);
|
||||
--color-red-tint-10: --alpha(var(--color-red-500) / 10%);
|
||||
|
||||
/* Green scale */
|
||||
--color-green-25: #F6FEF9;
|
||||
--color-green-50: #ECFDF3;
|
||||
--color-green-100: #D1FADF;
|
||||
--color-green-200: #A6F4C5;
|
||||
--color-green-300: #6CE9A6;
|
||||
--color-green-400: #32D583;
|
||||
--color-green-500: #12B76A;
|
||||
--color-green-600: #10A861;
|
||||
--color-green-700: #078C52;
|
||||
--color-green-800: #05603A;
|
||||
--color-green-900: #054F31;
|
||||
--color-green-tint-5: --alpha(var(--color-green-500) / 5%);
|
||||
--color-green-tint-10: --alpha(var(--color-green-500) / 10%);
|
||||
|
||||
/* Yellow scale */
|
||||
--color-yellow-25: #FFFCF5;
|
||||
--color-yellow-50: #FFFAEB;
|
||||
--color-yellow-100: #FEF0C7;
|
||||
--color-yellow-200: #FEDF89;
|
||||
--color-yellow-300: #FEC84B;
|
||||
--color-yellow-400: #FDB022;
|
||||
--color-yellow-500: #F79009;
|
||||
--color-yellow-600: #DC6803;
|
||||
--color-yellow-700: #B54708;
|
||||
--color-yellow-800: #93370D;
|
||||
--color-yellow-900: #7A2E0E;
|
||||
--color-yellow-tint-5: --alpha(var(--color-yellow-500) / 5%);
|
||||
--color-yellow-tint-10: --alpha(var(--color-yellow-500) / 10%);
|
||||
|
||||
/* Cyan scale */
|
||||
--color-cyan-25: #F5FEFF;
|
||||
--color-cyan-50: #ECFDFF;
|
||||
--color-cyan-100: #CFF9FE;
|
||||
--color-cyan-200: #A5F0FC;
|
||||
--color-cyan-300: #67E3F9;
|
||||
--color-cyan-400: #22CCEE;
|
||||
--color-cyan-500: #06AED4;
|
||||
--color-cyan-600: #088AB2;
|
||||
--color-cyan-700: #0E7090;
|
||||
--color-cyan-800: #155B75;
|
||||
--color-cyan-900: #155B75;
|
||||
--color-cyan-tint-5: --alpha(var(--color-cyan-500) / 5%);
|
||||
--color-cyan-tint-10: --alpha(var(--color-cyan-500) / 10%);
|
||||
|
||||
/* Blue scale */
|
||||
--color-blue-25: #F5FAFF;
|
||||
--color-blue-50: #EFF8FF;
|
||||
--color-blue-100: #D1E9FF;
|
||||
--color-blue-200: #B2DDFF;
|
||||
--color-blue-300: #84CAFF;
|
||||
--color-blue-400: #53B1FD;
|
||||
--color-blue-500: #2E90FA;
|
||||
--color-blue-600: #1570EF;
|
||||
--color-blue-700: #175CD3;
|
||||
--color-blue-800: #1849A9;
|
||||
--color-blue-900: #194185;
|
||||
--color-blue-tint-5: --alpha(var(--color-blue-500) / 5%);
|
||||
--color-blue-tint-10: --alpha(var(--color-blue-500) / 10%);
|
||||
|
||||
/* Indigo scale */
|
||||
--color-indigo-25: #F5F8FF;
|
||||
--color-indigo-50: #EFF4FF;
|
||||
--color-indigo-100: #E0EAFF;
|
||||
--color-indigo-200: #C7D7FE;
|
||||
--color-indigo-300: #A4BCFD;
|
||||
--color-indigo-400: #8098F9;
|
||||
--color-indigo-500: #6172F3;
|
||||
--color-indigo-600: #444CE7;
|
||||
--color-indigo-700: #3538CD;
|
||||
--color-indigo-800: #2D31A6;
|
||||
--color-indigo-900: #2D3282;
|
||||
--color-indigo-tint-5: --alpha(var(--color-indigo-500) / 5%);
|
||||
--color-indigo-tint-10: --alpha(var(--color-indigo-500) / 10%);
|
||||
|
||||
/* Violet scale */
|
||||
--color-violet-25: #FBFAFF;
|
||||
--color-violet-50: #F5F3FF;
|
||||
--color-violet-100: #ECE9FE;
|
||||
--color-violet-200: #DDD6FE;
|
||||
--color-violet-300: #C3B5FD;
|
||||
--color-violet-400: #A48AFB;
|
||||
--color-violet-500: #875BF7;
|
||||
--color-violet-600: #7839EE;
|
||||
--color-violet-700: #6927DA;
|
||||
--color-violet-tint-5: --alpha(var(--color-violet-500) / 5%);
|
||||
--color-violet-tint-10: --alpha(var(--color-violet-500) / 10%);
|
||||
|
||||
/* Fuchsia scale */
|
||||
--color-fuchsia-25: #FEFAFF;
|
||||
--color-fuchsia-50: #FDF4FF;
|
||||
--color-fuchsia-100: #FBE8FF;
|
||||
--color-fuchsia-200: #F6D0FE;
|
||||
--color-fuchsia-300: #EEAAFD;
|
||||
--color-fuchsia-400: #E478FA;
|
||||
--color-fuchsia-500: #D444F1;
|
||||
--color-fuchsia-600: #BA24D5;
|
||||
--color-fuchsia-700: #9F1AB1;
|
||||
--color-fuchsia-800: #821890;
|
||||
--color-fuchsia-900: #6F1877;
|
||||
--color-fuchsia-tint-5: --alpha(var(--color-fuchsia-500) / 5%);
|
||||
--color-fuchsia-tint-10: --alpha(var(--color-fuchsia-500) / 10%);
|
||||
|
||||
/* Pink scale */
|
||||
--color-pink-25: #FFFAFC;
|
||||
--color-pink-50: #FEF0F7;
|
||||
--color-pink-100: #FFD1E2;
|
||||
--color-pink-200: #FFB1CE;
|
||||
--color-pink-300: #FD8FBA;
|
||||
--color-pink-400: #F86BA7;
|
||||
--color-pink-500: #F23E94;
|
||||
--color-pink-600: #D5327F;
|
||||
--color-pink-700: #BA256B;
|
||||
--color-pink-800: #9E1958;
|
||||
--color-pink-900: #840B45;
|
||||
--color-pink-tint-5: --alpha(var(--color-pink-500) / 5%);
|
||||
--color-pink-tint-10: --alpha(var(--color-pink-500) / 10%);
|
||||
|
||||
/* Orange scale */
|
||||
--color-orange-25: #FFF9F5;
|
||||
--color-orange-50: #FFF4ED;
|
||||
--color-orange-100: #FFE6D5;
|
||||
--color-orange-200: #FFD6AE;
|
||||
--color-orange-300: #FF9C66;
|
||||
--color-orange-400: #FF692E;
|
||||
--color-orange-500: #FF4405;
|
||||
--color-orange-600: #E62E05;
|
||||
--color-orange-700: #BC1B06;
|
||||
--color-orange-800: #97180C;
|
||||
--color-orange-900: #771A0D;
|
||||
--color-orange-tint-5: --alpha(var(--color-orange-500) / 5%);
|
||||
--color-orange-tint-10: --alpha(var(--color-orange-500) / 10%);
|
||||
|
||||
/* Border radius overrides */
|
||||
--border-radius-md: 8px;
|
||||
--border-radius-lg: 10px;
|
||||
|
||||
--shadow-xs: 0px 1px 2px 0px --alpha(var(--color-black) / 6%);
|
||||
--shadow-sm: 0px 1px 6px 0px --alpha(var(--color-black) / 6%);
|
||||
--shadow-md: 0px 4px 8px -2px --alpha(var(--color-black) / 6%);
|
||||
--shadow-lg: 0px 12px 16px -4px --alpha(var(--color-black) / 6%);
|
||||
--shadow-xl: 0px 20px 24px -4px --alpha(var(--color-black) / 6%);
|
||||
}
|
||||
|
||||
/* Custom shadow borders used for surfaces / containers */
|
||||
@utility shadow-border-xs {
|
||||
box-shadow: var(--shadow-xs), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
}
|
||||
|
||||
@utility shadow-border-sm {
|
||||
box-shadow: var(--shadow-sm), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
}
|
||||
|
||||
@utility shadow-border-md {
|
||||
box-shadow: var(--shadow-md), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
}
|
||||
|
||||
@utility shadow-border-lg {
|
||||
box-shadow: var(--shadow-lg), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
}
|
||||
|
||||
@utility shadow-border-xl {
|
||||
box-shadow: var(--shadow-xl), 0px 0px 0px 1px var(--color-alpha-black-50);
|
||||
}
|
||||
|
||||
/* Design system color utilities */
|
||||
@utility text-primary {
|
||||
@apply text-gray-900;
|
||||
}
|
||||
|
||||
@utility text-secondary {
|
||||
@apply text-gray-500;
|
||||
}
|
||||
|
||||
@utility text-subdued {
|
||||
@apply text-gray-400;
|
||||
}
|
||||
|
||||
@utility text-link {
|
||||
@apply text-blue-600;
|
||||
}
|
||||
|
||||
@utility bg-surface {
|
||||
@apply bg-gray-50 hover:bg-gray-100;
|
||||
}
|
||||
|
||||
@utility bg-surface-inset {
|
||||
@apply bg-gray-100 hover:bg-gray-200;
|
||||
}
|
||||
|
||||
@utility bg-container {
|
||||
@apply bg-white hover:bg-gray-50;
|
||||
}
|
||||
|
||||
@utility bg-container-inset {
|
||||
@apply bg-gray-50 hover:bg-gray-100;
|
||||
}
|
||||
|
||||
@utility bg-inverse {
|
||||
@apply bg-gray-800 hover:bg-gray-700;
|
||||
}
|
||||
|
||||
@utility bg-overlay {
|
||||
@apply bg-alpha-black-200;
|
||||
}
|
||||
|
||||
@utility border-primary {
|
||||
@apply border-alpha-black-300;
|
||||
}
|
||||
|
||||
@utility border-secondary {
|
||||
@apply border-alpha-black-200;
|
||||
}
|
||||
|
||||
@utility border-tertiary {
|
||||
@apply border-alpha-black-100;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
details>summary::-webkit-details-marker {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
details>summary {
|
||||
@apply list-none;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] {
|
||||
@apply py-2 pr-2 space-y-0.5 overflow-y-auto;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] option {
|
||||
@apply py-2 rounded-md;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] option:checked {
|
||||
@apply after:content-['\2713'] bg-white after:text-gray-500 after:ml-2;
|
||||
}
|
||||
|
||||
select[multiple="multiple"] option:active,
|
||||
select[multiple="multiple"] option:focus {
|
||||
@apply bg-white;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
/* Buttons */
|
||||
.btn {
|
||||
@apply px-3 py-2 rounded-lg text-sm font-medium cursor-pointer disabled:cursor-not-allowed focus:outline-gray-500;
|
||||
}
|
||||
|
||||
.btn--primary {
|
||||
@apply bg-gray-900 text-white hover:bg-gray-700 disabled:bg-gray-50 disabled:hover:bg-gray-50 disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.btn--secondary {
|
||||
@apply bg-gray-50 hover:bg-gray-100 text-gray-900;
|
||||
}
|
||||
|
||||
.btn--outline {
|
||||
@apply border border-alpha-black-200 text-gray-900 hover:bg-gray-50 disabled:bg-gray-50 disabled:hover:bg-gray-50 disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.btn--ghost {
|
||||
@apply border border-transparent text-gray-900 hover:bg-gray-50;
|
||||
}
|
||||
|
||||
.btn--destructive {
|
||||
@apply bg-red-500 text-white hover:bg-red-600 disabled:bg-red-50 disabled:hover:bg-red-50 disabled:text-red-400;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
.form-field {
|
||||
@apply flex flex-col gap-1 relative px-3 py-2 rounded-md border bg-white border-alpha-black-100 shadow-xs w-full;
|
||||
@apply focus-within:border-gray-900 focus-within:shadow-none focus-within:ring-4 focus-within:ring-gray-100;
|
||||
}
|
||||
|
||||
.form-field__label {
|
||||
@apply block text-xs text-gray-500 peer-disabled:text-gray-400;
|
||||
}
|
||||
|
||||
.form-field__input {
|
||||
@apply border-none bg-transparent text-sm opacity-100 w-full p-0;
|
||||
@apply focus:opacity-100 focus:outline-hidden focus:ring-0;
|
||||
@apply placeholder-shown:opacity-50;
|
||||
@apply disabled:text-gray-400;
|
||||
@apply text-ellipsis overflow-hidden whitespace-nowrap;
|
||||
|
||||
&select {
|
||||
@apply pr-8;
|
||||
}
|
||||
}
|
||||
|
||||
.form-field__radio {
|
||||
@apply text-gray-900;
|
||||
}
|
||||
|
||||
.form-field__submit {
|
||||
@apply cursor-pointer rounded-lg bg-black p-3 text-center text-white hover:bg-gray-700;
|
||||
}
|
||||
|
||||
/* Checkboxes */
|
||||
.checkbox {
|
||||
&[type='checkbox'] {
|
||||
@apply rounded-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox--light {
|
||||
&[type='checkbox'] {
|
||||
@apply border-alpha-black-200 checked:bg-gray-900 checked:ring-gray-900 focus:ring-gray-900 focus-visible:ring-gray-900 checked:hover:bg-gray-500;
|
||||
}
|
||||
|
||||
&[type='checkbox']:disabled {
|
||||
@apply cursor-not-allowed opacity-80 bg-gray-50 border-gray-200 checked:bg-gray-400 checked:ring-gray-400;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox--dark {
|
||||
&[type='checkbox'] {
|
||||
@apply ring-gray-900 checked:text-white;
|
||||
}
|
||||
|
||||
&[type='checkbox']:disabled {
|
||||
@apply cursor-not-allowed opacity-80 ring-gray-600;
|
||||
}
|
||||
|
||||
&[type='checkbox']:checked {
|
||||
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='111827' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
|
||||
}
|
||||
}
|
||||
|
||||
/* Switches */
|
||||
.switch {
|
||||
@apply block bg-gray-100 w-9 h-5 rounded-full cursor-pointer;
|
||||
@apply after:content-[''] after:block after:absolute after:top-0.5 after:left-0.5 after:bg-white after:w-4 after:h-4 after:rounded-full after:transition-transform after:duration-300 after:ease-in-out;
|
||||
@apply peer-checked:bg-green-600 peer-checked:after:translate-x-4;
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
.prose {
|
||||
@apply max-w-none;
|
||||
|
||||
h2 {
|
||||
@apply text-xl font-medium;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-lg font-medium;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply m-0;
|
||||
}
|
||||
|
||||
details {
|
||||
@apply mb-4 rounded-xl mt-3.5;
|
||||
}
|
||||
|
||||
summary {
|
||||
@apply flex items-center gap-1;
|
||||
}
|
||||
|
||||
video {
|
||||
@apply m-0 rounded-b-xl;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tooltips */
|
||||
.tooltip {
|
||||
@apply hidden absolute;
|
||||
}
|
||||
}
|
|
@ -76,12 +76,12 @@ module AccountsHelper
|
|||
{
|
||||
"CreditCard" => { text: "text-red-500", bg: "bg-red-500", bg_transparent: "bg-red-500/10", fill: "fill-red-500", hex: "#F13636" },
|
||||
"Loan" => { text: "text-fuchsia-500", bg: "bg-fuchsia-500", bg_transparent: "bg-fuchsia-500/10", fill: "fill-fuchsia-500", hex: "#D444F1" },
|
||||
"OtherLiability" => { text: "text-gray-500", bg: "bg-gray-500", bg_transparent: "bg-gray-500/10", fill: "fill-gray-500", hex: "#737373" },
|
||||
"OtherLiability" => { text: "text-secondary", bg: "bg-gray-500", bg_transparent: "bg-gray-500/10", fill: "fill-gray-500", hex: "#737373" },
|
||||
"Depository" => { text: "text-violet-500", bg: "bg-violet-500", bg_transparent: "bg-violet-500/10", fill: "fill-violet-500", hex: "#875BF7" },
|
||||
"Investment" => { text: "text-blue-600", bg: "bg-blue-600", bg_transparent: "bg-blue-600/10", fill: "fill-blue-600", hex: "#1570EF" },
|
||||
"OtherAsset" => { text: "text-green-500", bg: "bg-green-500", bg_transparent: "bg-green-500/10", fill: "fill-green-500", hex: "#12B76A" },
|
||||
"Property" => { text: "text-cyan-500", bg: "bg-cyan-500", bg_transparent: "bg-cyan-500/10", fill: "fill-cyan-500", hex: "#06AED4" },
|
||||
"Vehicle" => { text: "text-pink-500", bg: "bg-pink-500", bg_transparent: "bg-pink-500/10", fill: "fill-pink-500", hex: "#F23E94" }
|
||||
}.fetch(accountable_type, { text: "text-gray-500", bg: "bg-gray-500", bg_transparent: "bg-gray-500/10", fill: "fill-gray-500", hex: "#737373" })
|
||||
}.fetch(accountable_type, { text: "text-secondary", bg: "bg-gray-500", bg_transparent: "bg-gray-500/10", fill: "fill-gray-500", hex: "#737373" })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,8 +76,8 @@ module ApplicationHelper
|
|||
is_current = current_page?(path) || (request.path.start_with?(path) && path != "/")
|
||||
|
||||
classes = [
|
||||
"flex items-center gap-2 px-3 py-2 rounded-xl border text-sm font-medium text-gray-500",
|
||||
(is_current ? "bg-white text-gray-900 shadow-xs border-alpha-black-50" : "hover:bg-gray-100 border-transparent")
|
||||
"flex items-center gap-2 px-3 py-2 rounded-xl border text-sm font-medium text-secondary",
|
||||
(is_current ? "bg-white text-primary shadow-xs border-alpha-black-50" : "hover:bg-gray-100 border-transparent")
|
||||
].compact.join(" ")
|
||||
|
||||
link_to path, **options.merge(class: classes), aria: { current: ("page" if current_page?(path)) } do
|
||||
|
@ -106,7 +106,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def trend_styles(trend)
|
||||
fallback = { bg_class: "bg-gray-500/5", text_class: "text-gray-500", symbol: "", icon: "minus" }
|
||||
fallback = { bg_class: "bg-gray-500/5", text_class: "text-secondary", symbol: "", icon: "minus" }
|
||||
return fallback if trend.nil? || trend.direction.flat?
|
||||
|
||||
bg_class, text_class, symbol, icon = case trend.direction
|
||||
|
@ -115,7 +115,7 @@ module ApplicationHelper
|
|||
when "down"
|
||||
trend.favorable_direction.down? ? [ "bg-green-500/5", "text-green-500", "-", "arrow-down" ] : [ "bg-red-500/5", "text-red-500", "-", "arrow-down" ]
|
||||
when "flat"
|
||||
[ "bg-gray-500/5", "text-gray-500", "", "minus" ]
|
||||
[ "bg-gray-500/5", "text-secondary", "", "minus" ]
|
||||
else
|
||||
raise ArgumentError, "Invalid trend direction: #{trend.direction}"
|
||||
end
|
||||
|
|
|
@ -17,7 +17,7 @@ module FormsHelper
|
|||
end
|
||||
end
|
||||
|
||||
def period_select(form:, selected:, classes: "border border-alpha-black-100 shadow-xs rounded-lg text-sm pr-7 cursor-pointer text-gray-900 focus:outline-hidden focus:ring-0")
|
||||
def period_select(form:, selected:, classes: "border border-tertiary shadow-xs rounded-lg text-sm pr-7 cursor-pointer text-primary focus:outline-hidden focus:ring-0")
|
||||
periods_for_select = [
|
||||
%w[CWD current_week], # Current Week to Date
|
||||
%w[7D last_7_days],
|
||||
|
@ -39,7 +39,7 @@ end
|
|||
|
||||
private
|
||||
def radio_tab_contents(label:, icon:)
|
||||
tag.div(class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-gray-400 group-has-checked:bg-white group-has-checked:text-gray-800 group-has-checked:shadow-sm") do
|
||||
tag.div(class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-subdued group-has-checked:bg-white group-has-checked:text-gray-800 group-has-checked:shadow-sm") do
|
||||
concat lucide_icon(icon, class: "w-5 h-5")
|
||||
concat tag.span(label, class: "group-has-checked:font-semibold")
|
||||
end
|
||||
|
|
|
@ -45,7 +45,7 @@ module ImportsHelper
|
|||
end
|
||||
|
||||
def cell_class(row, field)
|
||||
base = "text-sm focus:ring-gray-900 focus:border-gray-900 w-full max-w-full disabled:text-gray-400"
|
||||
base = "text-sm focus:ring-gray-900 focus:border-gray-900 w-full max-w-full disabled:text-subdued"
|
||||
|
||||
row.valid? # populate errors
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ module MenusHelper
|
|||
end
|
||||
|
||||
def contextual_menu_modal_action_item(label, url, icon: "pencil-line", turbo_frame: :modal)
|
||||
link_to url, class: "flex items-center rounded-lg text-gray-900 hover:bg-gray-50 py-2 px-3 gap-2", data: { turbo_frame: } do
|
||||
concat(lucide_icon(icon, class: "shrink-0 w-5 h-5 text-gray-500"))
|
||||
link_to url, class: "flex items-center rounded-lg text-primary hover:bg-gray-50 py-2 px-3 gap-2", data: { turbo_frame: } do
|
||||
concat(lucide_icon(icon, class: "shrink-0 w-5 h-5 text-secondary"))
|
||||
concat(tag.span(label, class: "text-sm"))
|
||||
end
|
||||
end
|
||||
|
@ -26,7 +26,7 @@ module MenusHelper
|
|||
private
|
||||
def contextual_menu_icon
|
||||
tag.button class: "flex hover:bg-gray-100 p-2 rounded cursor-pointer", data: { menu_target: "button" } do
|
||||
lucide_icon "more-horizontal", class: "w-5 h-5 text-gray-500"
|
||||
lucide_icon "more-horizontal", class: "w-5 h-5 text-secondary"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -401,11 +401,11 @@ export default class extends Controller {
|
|||
up:
|
||||
datum.trend.favorable_direction === "up"
|
||||
? "var(--color-success)"
|
||||
: "var(--color-error)",
|
||||
: "var(--color-destructive)",
|
||||
down:
|
||||
datum.trend.favorable_direction === "down"
|
||||
? "var(--color-success)"
|
||||
: "var(--color-error)",
|
||||
: "var(--color-destructive)",
|
||||
flat: "var(--color-gray-500)",
|
||||
}[datum.trend.direction];
|
||||
}
|
||||
|
@ -509,7 +509,7 @@ export default class extends Controller {
|
|||
if (this._trendDirection === this._favorableDirection) {
|
||||
return "var(--color-green-500)";
|
||||
}
|
||||
return "var(--color-error)";
|
||||
return "var(--color-destructive)";
|
||||
}
|
||||
|
||||
get _trendDirection() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="flex flex-col items-center justify-center py-40">
|
||||
<p class="text-gray-500 mb-2"><%= t(".title") %></p>
|
||||
<p class="text-gray-400 max-w-xs text-center"><%= t(".description") %></p>
|
||||
<p class="text-secondary mb-2"><%= t(".title") %></p>
|
||||
<p class="text-subdued max-w-xs text-center"><%= t(".description") %></p>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<%# locals: (date:, entries:, content:, selectable:, totals: false) %>
|
||||
<div id="entry-group-<%= date %>" class="bg-gray-25 rounded-xl p-1 w-full" data-bulk-select-target="group">
|
||||
<div class="py-2 px-4 flex items-center justify-between font-medium text-xs text-gray-500">
|
||||
<div class="py-2 px-4 flex items-center justify-between font-medium text-xs text-secondary">
|
||||
<div class="flex pl-0.5 items-center gap-4">
|
||||
<% if selectable %>
|
||||
<%= check_box_tag "#{date}_entries_selection",
|
||||
class: ["maybe-checkbox maybe-checkbox--light", "hidden": entries.size == 0],
|
||||
class: ["checkbox checkbox--light", "hidden": entries.size == 0],
|
||||
id: "selection_entry_#{date}",
|
||||
data: { action: "bulk-select#toggleGroupSelection" } %>
|
||||
<% end %>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="bg-white space-y-4 p-5 border border-alpha-black-25 rounded-xl shadow-xs">
|
||||
<div class="p-5 flex justify-center items-center">
|
||||
<%= tag.p t(".loading"), class: "text-gray-500 animate-pulse text-sm" %>
|
||||
<%= tag.p t(".loading"), class: "text-secondary animate-pulse text-sm" %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="fixed bottom-6 z-10 flex items-center justify-between rounded-xl bg-gray-900 px-4 text-sm text-white w-[420px] py-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<%= check_box_tag "entry_selection", 1, true, class: "maybe-checkbox maybe-checkbox--dark", data: { action: "bulk-select#deselectAll" } %>
|
||||
<%= check_box_tag "entry_selection", 1, true, class: "checkbox checkbox--dark", data: { action: "bulk-select#deselectAll" } %>
|
||||
|
||||
<p data-bulk-select-target="selectionBarText"></p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1 text-gray-500">
|
||||
<div class="flex items-center gap-1 text-secondary">
|
||||
<%= form_with url: bulk_delete_account_transactions_path, data: { turbo_confirm: true, turbo_frame: "_top" } do %>
|
||||
<button type="button" data-bulk-select-scope-param="bulk_delete" data-action="bulk-select#submitBulkRequest" class="p-1.5 group hover:bg-gray-700 flex items-center justify-center rounded-md" title="Delete">
|
||||
<%= lucide_icon "trash-2", class: "w-5 group-hover:text-white" %>
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
<% currency = Money::Currency.new(account.currency) %>
|
||||
|
||||
<div class="grid grid-cols-12 items-center text-gray-900 text-sm font-medium p-4">
|
||||
<div class="grid grid-cols-12 items-center text-primary text-sm font-medium p-4">
|
||||
<div class="col-span-4 flex items-center gap-4">
|
||||
<%= render "shared/circle_logo", name: currency.iso_code %>
|
||||
|
||||
<div class="space-y-0.5">
|
||||
<%= tag.p t(".brokerage_cash"), class: "text-gray-900" %>
|
||||
<%= tag.p account.currency, class: "text-gray-500 text-xs uppercase" %>
|
||||
<%= tag.p t(".brokerage_cash"), class: "text-primary" %>
|
||||
<%= tag.p account.currency, class: "text-secondary text-xs uppercase" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
|
||||
<div class="col-span-2 text-right">
|
||||
<%= tag.p "--", class: "text-gray-500" %>
|
||||
<%= tag.p "--", class: "text-secondary" %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 text-right">
|
||||
|
@ -27,6 +27,6 @@
|
|||
</div>
|
||||
|
||||
<div class="col-span-2 text-right">
|
||||
<%= tag.p "--", class: "text-gray-500" %>
|
||||
<%= tag.p "--", class: "text-secondary" %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<%# locals: (holding:) %>
|
||||
|
||||
<%= turbo_frame_tag dom_id(holding) do %>
|
||||
<div class="grid grid-cols-12 items-center text-gray-900 text-sm font-medium p-4">
|
||||
<div class="grid grid-cols-12 items-center text-primary text-sm font-medium p-4">
|
||||
<div class="col-span-4 flex items-center gap-4">
|
||||
<%= image_tag "https://logo.synthfinance.com/ticker/#{holding.ticker}", class: "w-9 h-9 rounded-full", loading: "lazy" %>
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
|||
<%= link_to holding.name, account_holding_path(holding), data: { turbo_frame: :drawer }, class: "hover:underline" %>
|
||||
|
||||
<% if holding.amount %>
|
||||
<%= tag.p holding.ticker, class: "text-gray-500 text-xs uppercase" %>
|
||||
<%= tag.p holding.ticker, class: "text-secondary text-xs uppercase" %>
|
||||
<% else %>
|
||||
<%= render "missing_price_tooltip" %>
|
||||
<% end %>
|
||||
|
@ -21,22 +21,22 @@
|
|||
<%= render "shared/progress_circle", progress: holding.weight, text_class: "text-blue-500" %>
|
||||
<%= tag.p number_to_percentage(holding.weight, precision: 1) %>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "text-gray-500 mb-5" %>
|
||||
<%= tag.p "--", class: "text-secondary mb-5" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 text-right">
|
||||
<%= tag.p format_money holding.avg_cost %>
|
||||
<%= tag.p t(".per_share"), class: "font-normal text-gray-500" %>
|
||||
<%= tag.p t(".per_share"), class: "font-normal text-secondary" %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 text-right">
|
||||
<% if holding.amount_money %>
|
||||
<%= tag.p format_money holding.amount_money %>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "text-gray-500" %>
|
||||
<%= tag.p "--", class: "text-secondary" %>
|
||||
<% end %>
|
||||
<%= tag.p t(".shares", qty: number_with_precision(holding.qty, precision: 1)), class: "font-normal text-gray-500" %>
|
||||
<%= tag.p t(".shares", qty: number_with_precision(holding.qty, precision: 1)), class: "font-normal text-secondary" %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 text-right">
|
||||
|
@ -44,7 +44,7 @@
|
|||
<%= tag.p format_money(holding.trend.value), style: "color: #{holding.trend.color};" %>
|
||||
<%= tag.p "(#{number_to_percentage(holding.trend.percent, precision: 1)})", style: "color: #{holding.trend.color};" %>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "text-gray-500 mb-4" %>
|
||||
<%= tag.p "--", class: "text-secondary mb-4" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,14 +5,14 @@
|
|||
<%= link_to new_account_trade_path(account_id: @account.id),
|
||||
id: dom_id(@account, "new_trade"),
|
||||
data: { turbo_frame: :modal },
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-gray-900 p-2 rounded-lg" do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-900") %>
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-primary p-2 rounded-lg" do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-primary") %>
|
||||
<%= tag.span t(".new_holding"), class: "text-sm" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-gray-25 p-1">
|
||||
<div class="grid grid-cols-12 items-center uppercase text-xs font-medium text-gray-500 px-4 py-2">
|
||||
<div class="grid grid-cols-12 items-center uppercase text-xs font-medium text-secondary px-4 py-2">
|
||||
<%= tag.p t(".name"), class: "col-span-4" %>
|
||||
<%= tag.p t(".weight"), class: "col-span-2 justify-self-end" %>
|
||||
<%= tag.p t(".cost"), class: "col-span-2 justify-self-end" %>
|
||||
|
@ -26,7 +26,7 @@
|
|||
<%= render "account/holdings/ruler" %>
|
||||
<%= render partial: "account/holdings/holding", collection: @account.current_holdings, spacer_template: "ruler" %>
|
||||
<% else %>
|
||||
<p class="text-gray-500 text-sm p-4"><%= t(".no_holdings") %></p>
|
||||
<p class="text-secondary text-sm p-4"><%= t(".no_holdings") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,43 +2,43 @@
|
|||
<div class="space-y-4">
|
||||
<header class="flex justify-between">
|
||||
<div>
|
||||
<%= tag.h3 @holding.name, class: "text-2xl font-medium text-gray-900" %>
|
||||
<%= tag.p @holding.ticker, class: "text-sm text-gray-500" %>
|
||||
<%= tag.h3 @holding.name, class: "text-2xl font-medium text-primary" %>
|
||||
<%= tag.p @holding.ticker, class: "text-sm text-secondary" %>
|
||||
</div>
|
||||
|
||||
<%= image_tag "https://logo.synthfinance.com/ticker/#{@holding.ticker}", loading: "lazy", class: "w-9 h-9 rounded-full" %>
|
||||
</header>
|
||||
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4><%= t(".overview") %></h4>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="pb-4">
|
||||
<dl class="space-y-3 px-3 py-2">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".ticker_label") %></dt>
|
||||
<dd class="text-gray-900"><%= @holding.ticker %></dd>
|
||||
<dt class="text-secondary"><%= t(".ticker_label") %></dt>
|
||||
<dd class="text-primary"><%= @holding.ticker %></dd>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".current_market_price_label") %></dt>
|
||||
<dd class="text-gray-900"><%= @holding.security.current_price ? format_money(@holding.security.current_price) : t(".unknown") %></dd>
|
||||
<dt class="text-secondary"><%= t(".current_market_price_label") %></dt>
|
||||
<dd class="text-primary"><%= @holding.security.current_price ? format_money(@holding.security.current_price) : t(".unknown") %></dd>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".portfolio_weight_label") %></dt>
|
||||
<dd class="text-gray-900"><%= @holding.weight ? number_to_percentage(@holding.weight, precision: 2) : t(".unknown") %></dd>
|
||||
<dt class="text-secondary"><%= t(".portfolio_weight_label") %></dt>
|
||||
<dd class="text-primary"><%= @holding.weight ? number_to_percentage(@holding.weight, precision: 2) : t(".unknown") %></dd>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".avg_cost_label") %></dt>
|
||||
<dd class="text-gray-900"><%= @holding.avg_cost ? format_money(@holding.avg_cost) : t(".unknown") %></dd>
|
||||
<dt class="text-secondary"><%= t(".avg_cost_label") %></dt>
|
||||
<dd class="text-primary"><%= @holding.avg_cost ? format_money(@holding.avg_cost) : t(".unknown") %></dd>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".trend_label") %></dt>
|
||||
<dt class="text-secondary"><%= t(".trend_label") %></dt>
|
||||
<dd style="color: <%= @holding.trend&.color %>;">
|
||||
<%= @holding.trend ? render("shared/trend_change", trend: @holding.trend) : t(".unknown") %>
|
||||
</dd>
|
||||
|
@ -48,9 +48,9 @@
|
|||
</details>
|
||||
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4><%= t(".history") %></h4>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="space-y-2">
|
||||
|
@ -67,7 +67,7 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<p class="text-gray-500 text-xs uppercase"><%= l(trade_entry.date, format: :long) %></p>
|
||||
<p class="text-secondary text-xs uppercase"><%= l(trade_entry.date, format: :long) %></p>
|
||||
|
||||
<p><%= t(
|
||||
".trade_history_entry",
|
||||
|
@ -81,29 +81,29 @@
|
|||
</ul>
|
||||
|
||||
<% else %>
|
||||
<p class="text-gray-500">No trade history available for this holding.</p>
|
||||
<p class="text-secondary">No trade history available for this holding.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4><%= t(".settings") %></h4>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="pb-4">
|
||||
<div class="flex items-center justify-between gap-2 p-3">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900"><%= t(".delete_title") %></h4>
|
||||
<p class="text-gray-500"><%= t(".delete_subtitle") %></p>
|
||||
<h4 class="text-primary"><%= t(".delete_title") %></h4>
|
||||
<p class="text-secondary"><%= t(".delete_subtitle") %></p>
|
||||
</div>
|
||||
|
||||
<%= button_to t(".delete"),
|
||||
account_holding_path(@holding),
|
||||
method: :delete,
|
||||
class: "rounded-lg px-3 py-2 text-red-500 text-sm font-medium border border-alpha-black-200",
|
||||
class: "rounded-lg px-3 py-2 text-red-500 text-sm font-medium border border-secondary",
|
||||
data: { turbo_confirm: true } %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<div id="<%= dom_id(entry, :header) %>">
|
||||
<%= tag.header class: "mb-4 space-y-1" do %>
|
||||
<span class="text-gray-500 text-sm">
|
||||
<span class="text-secondary text-sm">
|
||||
<%= entry.amount.negative? ? t(".sell") : t(".buy") %>
|
||||
</span>
|
||||
|
||||
|
@ -12,13 +12,13 @@
|
|||
<%= format_money entry.amount_money %>
|
||||
</span>
|
||||
|
||||
<span class="text-lg text-gray-500">
|
||||
<span class="text-lg text-secondary">
|
||||
<%= entry.currency %>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<span class="text-sm text-gray-500">
|
||||
<span class="text-sm text-secondary">
|
||||
<%= I18n.l(entry.date, format: :long) %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
@ -30,32 +30,32 @@
|
|||
<div class="pb-4">
|
||||
<dl class="space-y-3 px-3 py-2">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".symbol_label") %></dt>
|
||||
<dd class="text-gray-900"><%= trade.security.ticker %></dd>
|
||||
<dt class="text-secondary"><%= t(".symbol_label") %></dt>
|
||||
<dd class="text-primary"><%= trade.security.ticker %></dd>
|
||||
</div>
|
||||
|
||||
<% if trade.qty.positive? %>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".purchase_qty_label") %></dt>
|
||||
<dd class="text-gray-900"><%= trade.qty.abs %></dd>
|
||||
<dt class="text-secondary"><%= t(".purchase_qty_label") %></dt>
|
||||
<dd class="text-primary"><%= trade.qty.abs %></dd>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".purchase_price_label") %></dt>
|
||||
<dd class="text-gray-900"><%= format_money trade.price_money %></dd>
|
||||
<dt class="text-secondary"><%= t(".purchase_price_label") %></dt>
|
||||
<dd class="text-primary"><%= format_money trade.price_money %></dd>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if trade.security.current_price.present? %>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".current_market_price_label") %></dt>
|
||||
<dd class="text-gray-900"><%= format_money trade.security.current_price %></dd>
|
||||
<dt class="text-secondary"><%= t(".current_market_price_label") %></dt>
|
||||
<dd class="text-primary"><%= format_money trade.security.current_price %></dd>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if trade.qty.positive? && trade.unrealized_gain_loss.present? %>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500"><%= t(".total_return_label") %></dt>
|
||||
<dt class="text-secondary"><%= t(".total_return_label") %></dt>
|
||||
<dd style="color: <%= trade.unrealized_gain_loss.color %>;">
|
||||
<%= render "shared/trend_change", trend: trade.unrealized_gain_loss %>
|
||||
</dd>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="fixed bottom-6 z-10 flex items-center justify-between rounded-xl bg-gray-900 px-4 text-sm text-white w-[420px] py-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<%= check_box_tag "entry_selection", 1, true, class: "maybe-checkbox maybe-checkbox--dark", data: { action: "bulk-select#deselectAll" } %>
|
||||
<%= check_box_tag "entry_selection", 1, true, class: "checkbox checkbox--dark", data: { action: "bulk-select#deselectAll" } %>
|
||||
|
||||
<p data-bulk-select-target="selectionBarText"></p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1 text-gray-500">
|
||||
<div class="flex items-center gap-1 text-secondary">
|
||||
<%= form_with url: bulk_delete_account_transactions_path, data: { turbo_confirm: true, turbo_frame: "_top" } do %>
|
||||
<button type="button" data-bulk-select-scope-param="bulk_delete" data-action="bulk-select#submitBulkRequest" class="p-1.5 group hover:bg-gray-700 flex items-center justify-center rounded-md" title="Delete">
|
||||
<%= lucide_icon "trash-2", class: "w-5 group-hover:text-white" %>
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
<% trade, account = entry.account_trade, entry.account %>
|
||||
|
||||
<div class="grid grid-cols-12 items-center <%= entry.excluded ? "text-gray-400 bg-gray-25" : "text-gray-900" %> text-sm font-medium p-4">
|
||||
<div class="grid grid-cols-12 items-center <%= entry.excluded ? "text-subdued bg-gray-25" : "text-primary" %> text-sm font-medium p-4">
|
||||
<div class="col-span-6 flex items-center gap-4">
|
||||
<% if selectable %>
|
||||
<%= check_box_tag dom_id(entry, "selection"),
|
||||
class: "maybe-checkbox maybe-checkbox--light",
|
||||
class: "checkbox checkbox--light",
|
||||
data: { id: entry.id, "bulk-select-target": "row", action: "bulk-select#toggleRowSelection" } %>
|
||||
<% end %>
|
||||
|
||||
|
@ -43,10 +43,10 @@
|
|||
<div class="col-span-2 justify-self-end">
|
||||
<% if balance_trend&.trend %>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= tag.p format_money(balance_trend.trend.current), class: "font-medium text-sm text-gray-900" %>
|
||||
<%= tag.p format_money(balance_trend.trend.current), class: "font-medium text-sm text-primary" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "font-medium text-sm text-gray-400" %>
|
||||
<%= tag.p "--", class: "font-medium text-sm text-subdued" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
<h3 class="font-medium text-lg"><%= t(".trades") %></h3>
|
||||
<%= link_to new_account_trade_path(@account),
|
||||
id: dom_id(@account, "new_trade"),
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-gray-900 p-2 rounded-lg",
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-primary p-2 rounded-lg",
|
||||
data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-900") %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-primary") %>
|
||||
<span class="text-sm"><%= t(".new") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-25 rounded-xl grid grid-cols-12 items-center uppercase text-xs font-medium text-gray-500 px-5 py-3">
|
||||
<div class="bg-gray-25 rounded-xl grid grid-cols-12 items-center uppercase text-xs font-medium text-secondary px-5 py-3">
|
||||
<div class="pl-0.5 col-span-6 flex items-center gap-4">
|
||||
<%= check_box_tag "selection_entry",
|
||||
class: "maybe-checkbox maybe-checkbox--light",
|
||||
class: "checkbox checkbox--light",
|
||||
data: { action: "bulk-select#togglePageSelection" } %>
|
||||
<%= tag.p t(".trade") %>
|
||||
</div>
|
||||
|
@ -29,7 +29,7 @@
|
|||
</div>
|
||||
|
||||
<% if @entries.empty? %>
|
||||
<p class="text-gray-500 py-4"><%= t(".no_trades") %></p>
|
||||
<p class="text-secondary py-4"><%= t(".no_trades") %></p>
|
||||
<% else %>
|
||||
<div class="space-y-6">
|
||||
<%= entries_by_date(@entries) do |entries, _transfers| %>
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
data: { controller: "auto-submit-form" } do |f| %>
|
||||
<div class="flex cursor-pointer items-center gap-2 justify-between">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900"><%= t(".exclude_title") %></h4>
|
||||
<p class="text-gray-500"><%= t(".exclude_subtitle") %></p>
|
||||
<h4 class="text-primary"><%= t(".exclude_title") %></h4>
|
||||
<p class="text-secondary"><%= t(".exclude_subtitle") %></p>
|
||||
</div>
|
||||
|
||||
<div class="relative inline-block select-none">
|
||||
|
@ -77,7 +77,7 @@
|
|||
class: "sr-only peer",
|
||||
"data-auto-submit-form-target": "auto" %>
|
||||
<label for="account_entry_excluded"
|
||||
class="maybe-switch"></label>
|
||||
class="switch"></label>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
@ -85,15 +85,15 @@
|
|||
<!-- Delete Trade Form -->
|
||||
<div class="flex items-center justify-between gap-2 p-3">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900"><%= t(".delete_title") %></h4>
|
||||
<p class="text-gray-500"><%= t(".delete_subtitle") %></p>
|
||||
<h4 class="text-primary"><%= t(".delete_title") %></h4>
|
||||
<p class="text-secondary"><%= t(".delete_subtitle") %></p>
|
||||
</div>
|
||||
|
||||
<%= button_to t(".delete"),
|
||||
account_entry_path(@entry),
|
||||
method: :delete,
|
||||
class: "rounded-lg px-3 py-2 text-red-500 text-sm
|
||||
font-medium border border-alpha-black-200",
|
||||
font-medium border border-secondary",
|
||||
data: { turbo_confirm: true } %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<fieldset class="bg-gray-50 rounded-lg p-1 grid grid-flow-col justify-stretch gap-x-2">
|
||||
<%= radio_tab_tag form: f, name: :nature, value: :outflow, label: t(".expense"), icon: "minus-circle", checked: params[:nature] == "outflow" || params[:nature].nil? %>
|
||||
<%= radio_tab_tag form: f, name: :nature, value: :inflow, label: t(".income"), icon: "plus-circle", checked: params[:nature] == "inflow" %>
|
||||
<%= link_to new_transfer_path, data: { turbo_frame: :modal }, class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-gray-400 group-has-checked:bg-white group-has-checked:text-gray-800 group-has-checked:shadow-sm" do %>
|
||||
<%= link_to new_transfer_path, data: { turbo_frame: :modal }, class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-subdued group-has-checked:bg-white group-has-checked:text-gray-800 group-has-checked:shadow-sm" do %>
|
||||
<%= lucide_icon "arrow-right-left", class: "w-5 h-5" %>
|
||||
<%= tag.span t(".transfer") %>
|
||||
<% end %>
|
||||
|
|
|
@ -7,17 +7,17 @@
|
|||
<%= format_money -entry.amount_money %>
|
||||
</span>
|
||||
|
||||
<span class="text-lg text-gray-500">
|
||||
<span class="text-lg text-secondary">
|
||||
<%= entry.currency %>
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<% if entry.account_transaction.transfer? %>
|
||||
<%= lucide_icon "arrow-left-right", class: "text-gray-500 mt-1 w-5 h-5" %>
|
||||
<%= lucide_icon "arrow-left-right", class: "text-secondary mt-1 w-5 h-5" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<span class="text-sm text-gray-500">
|
||||
<span class="text-sm text-secondary">
|
||||
<%= I18n.l(entry.date, format: :long) %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<div class="fixed bottom-6 z-10 flex items-center justify-between rounded-xl bg-gray-900 px-4 text-sm text-white w-[420px] py-1.5">
|
||||
<div class="flex items-center gap-2">
|
||||
<%= check_box_tag "entry_selection", 1, true, class: "maybe-checkbox maybe-checkbox--dark", data: { action: "bulk-select#deselectAll" } %>
|
||||
<%= check_box_tag "entry_selection", 1, true, class: "checkbox checkbox--dark", data: { action: "bulk-select#deselectAll" } %>
|
||||
|
||||
<p data-bulk-select-target="selectionBarText"></p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1 text-gray-500">
|
||||
<div class="flex items-center gap-1 text-secondary">
|
||||
<%= turbo_frame_tag "bulk_transaction_edit_drawer" %>
|
||||
|
||||
<%= link_to bulk_edit_account_transactions_path,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<%# locals: (entry:, selectable: true, balance_trend: nil) %>
|
||||
|
||||
<div class="grid grid-cols-12 items-center text-gray-900 text-sm font-medium p-4 <%= @focused_record == entry ? "border border-gray-900 rounded-lg" : "" %>">
|
||||
<div class="grid grid-cols-12 items-center text-primary text-sm font-medium p-4 <%= @focused_record == entry ? "border border-gray-900 rounded-lg" : "" %>">
|
||||
<div class="pr-10 flex items-center gap-4 <%= balance_trend ? "col-span-6" : "col-span-8" %>">
|
||||
<% if selectable %>
|
||||
<%= check_box_tag dom_id(entry, "selection"),
|
||||
disabled: entry.entryable.transfer?,
|
||||
class: "maybe-checkbox maybe-checkbox--light",
|
||||
class: "checkbox checkbox--light",
|
||||
data: { id: entry.id, "bulk-select-target": "row", action: "bulk-select#toggleRowSelection" } %>
|
||||
<% end %>
|
||||
|
||||
|
@ -40,7 +40,7 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="text-gray-500 text-xs font-normal">
|
||||
<div class="text-secondary text-xs font-normal">
|
||||
<% if entry.entryable.transfer? %>
|
||||
<%= render "transfers/account_links", transfer: entry.entryable.transfer, is_inflow: entry.entryable.transfer_as_inflow.present? %>
|
||||
<% else %>
|
||||
|
@ -66,9 +66,9 @@
|
|||
<% if balance_trend %>
|
||||
<div class="col-span-2 justify-self-end">
|
||||
<% if balance_trend.trend %>
|
||||
<%= tag.p format_money(balance_trend.trend.current), class: "font-medium text-sm text-gray-900" %>
|
||||
<%= tag.p format_money(balance_trend.trend.current), class: "font-medium text-sm text-primary" %>
|
||||
<% else %>
|
||||
<%= tag.p "--", class: "font-medium text-sm text-gray-400" %>
|
||||
<%= tag.p "--", class: "font-medium text-sm text-subdued" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<%= button_to transfer_path(entry.account_transaction.transfer, transfer: { status: "confirmed" }),
|
||||
method: :patch,
|
||||
class: "text-gray-500 hover:text-gray-800 flex items-center justify-center",
|
||||
class: "text-secondary hover:text-gray-800 flex items-center justify-center",
|
||||
title: "Confirm match" do %>
|
||||
<%= lucide_icon "check", class: "w-4 h-4 text-indigo-400 hover:text-indigo-600" %>
|
||||
<% end %>
|
||||
|
@ -20,9 +20,9 @@
|
|||
<%= button_to transfer_path(entry.account_transaction.transfer, transfer: { status: "rejected" }),
|
||||
method: :patch,
|
||||
data: { turbo: false },
|
||||
class: "text-gray-500 hover:text-gray-800 flex items-center justify-center",
|
||||
class: "text-secondary hover:text-gray-800 flex items-center justify-center",
|
||||
title: "Reject match" do %>
|
||||
<%= lucide_icon "x", class: "w-4 h-4 text-gray-400 hover:text-gray-600" %>
|
||||
<%= lucide_icon "x", class: "w-4 h-4 text-subdued hover:text-gray-600" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
|
||||
<div class="space-y-2">
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4><%= t(".overview") %></h4>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="pb-6 space-y-2">
|
||||
|
@ -32,14 +32,14 @@
|
|||
</details>
|
||||
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2 text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4><%= t(".details") %></h4>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
<%= lucide_icon "chevron-down", class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="space-y-2">
|
||||
<%= form.collection_select :category_id, Current.family.categories.alphabetically, :id, :name, { prompt: t(".category_placeholder"), label: t(".category_label"), class: "text-gray-400" } %>
|
||||
<%= form.collection_select :merchant_id, Current.family.merchants.alphabetically, :id, :name, { prompt: t(".merchant_placeholder"), label: t(".merchant_label"), class: "text-gray-400" } %>
|
||||
<%= form.collection_select :category_id, Current.family.categories.alphabetically, :id, :name, { prompt: t(".category_placeholder"), label: t(".category_label"), class: "text-subdued" } %>
|
||||
<%= form.collection_select :merchant_id, Current.family.merchants.alphabetically, :id, :name, { prompt: t(".merchant_placeholder"), label: t(".merchant_label"), class: "text-subdued" } %>
|
||||
<%= form.text_area :notes, label: t(".note_label"), placeholder: t(".note_placeholder"), rows: 5 %>
|
||||
</div>
|
||||
</details>
|
||||
|
@ -49,7 +49,7 @@
|
|||
</div>
|
||||
|
||||
<div class="flex justify-end items-center gap-2">
|
||||
<%= link_to t(".cancel"), transactions_path, class: "text-sm font-medium text-gray-900 px-3 py-2" %>
|
||||
<%= link_to t(".cancel"), transactions_path, class: "text-sm font-medium text-primary px-3 py-2" %>
|
||||
|
||||
<%= tag.button t(".save"),
|
||||
type: "button",
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<div class="flex justify-between items-center">
|
||||
<h3 class="font-medium text-lg"><%= t(".transactions") %></h3>
|
||||
<%= link_to new_account_transaction_path(account_id: @account),
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-gray-900 p-2 rounded-lg",
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-primary p-2 rounded-lg",
|
||||
data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-900") %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-primary") %>
|
||||
<span class="text-sm"><%= t(".new") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</div>
|
||||
|
||||
<% if @entries.empty? %>
|
||||
<p class="text-gray-500 py-4"><%= t(".no_transactions") %></p>
|
||||
<p class="text-secondary py-4"><%= t(".no_transactions") %></p>
|
||||
<% else %>
|
||||
<div class="space-y-6">
|
||||
<%= entries_by_date(@entries) do |entries, _transfers| %>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
Current.family.categories.alphabetically,
|
||||
:id, :name,
|
||||
{ label: t(".category_label"),
|
||||
class: "text-gray-400", include_blank: t(".uncategorized") },
|
||||
class: "text-subdued", include_blank: t(".uncategorized") },
|
||||
"data-auto-submit-form-target": "auto" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
@ -70,7 +70,7 @@
|
|||
:id, :name,
|
||||
{ include_blank: t(".none"),
|
||||
label: t(".merchant_label"),
|
||||
class: "text-gray-400" },
|
||||
class: "text-subdued" },
|
||||
"data-auto-submit-form-target": "auto" %>
|
||||
|
||||
<%= ef.select :tag_ids,
|
||||
|
@ -105,8 +105,8 @@
|
|||
data: { controller: "auto-submit-form" } do |f| %>
|
||||
<div class="flex cursor-pointer items-center gap-4 justify-between">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900">One-time <%= @entry.amount.negative? ? "Income" : "Expense" %></h4>
|
||||
<p class="text-gray-500">One-time transactions will be excluded from certain budgeting calculations and reports to help you see what's really important.</p>
|
||||
<h4 class="text-primary">One-time <%= @entry.amount.negative? ? "Income" : "Expense" %></h4>
|
||||
<p class="text-secondary">One-time transactions will be excluded from certain budgeting calculations and reports to help you see what's really important.</p>
|
||||
</div>
|
||||
|
||||
<div class="relative inline-block select-none">
|
||||
|
@ -114,15 +114,15 @@
|
|||
class: "sr-only peer",
|
||||
"data-auto-submit-form-target": "auto" %>
|
||||
<label for="account_entry_excluded"
|
||||
class="maybe-switch"></label>
|
||||
class="switch"></label>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="flex items-center justify-between gap-4 p-3">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900">Transfer or Debt Payment?</h4>
|
||||
<p class="text-gray-500">Transfers and payments are special types of transactions that indicate money movement between 2 accounts.</p>
|
||||
<h4 class="text-primary">Transfer or Debt Payment?</h4>
|
||||
<p class="text-secondary">Transfers and payments are special types of transactions that indicate money movement between 2 accounts.</p>
|
||||
</div>
|
||||
|
||||
<%= link_to new_account_transaction_transfer_match_path(@entry), class: "btn btn--outline flex items-center gap-2", data: { turbo_frame: :modal } do %>
|
||||
|
@ -134,15 +134,15 @@
|
|||
<!-- Delete Transaction Form -->
|
||||
<div class="flex items-center justify-between gap-2 p-3">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900"><%= t(".delete_title") %></h4>
|
||||
<p class="text-gray-500"><%= t(".delete_subtitle") %></p>
|
||||
<h4 class="text-primary"><%= t(".delete_title") %></h4>
|
||||
<p class="text-secondary"><%= t(".delete_subtitle") %></p>
|
||||
</div>
|
||||
|
||||
<%= button_to t(".delete"),
|
||||
account_entry_path(@entry),
|
||||
method: :delete,
|
||||
class: "rounded-lg px-3 py-2 text-red-500 text-sm
|
||||
font-medium border border-alpha-black-200",
|
||||
font-medium border border-secondary",
|
||||
data: { turbo_confirm: true, turbo_frame: "_top" } %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<% if candidates.any? %>
|
||||
<div data-controller="transfer-match" class="space-y-2">
|
||||
<p class="text-sm text-gray-500">
|
||||
<p class="text-sm text-secondary">
|
||||
Select a method for matching your transactions.
|
||||
</p>
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="text-sm text-gray-500">
|
||||
<p class="text-sm text-secondary">
|
||||
We couldn't find any transactions to match from your other accounts.
|
||||
Please select an account and we will create a new inflow transaction for you.
|
||||
</p>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<%# locals: (entry:) %>
|
||||
|
||||
<%= tag.header class: "mb-4 space-y-1", id: dom_id(entry, :header) do %>
|
||||
<span class="text-gray-500 text-sm">
|
||||
<span class="text-secondary text-sm">
|
||||
<%= t(".balance") %>
|
||||
</span>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<span class="text-sm text-gray-500">
|
||||
<span class="text-sm text-secondary">
|
||||
<%= I18n.l(entry.date, format: :long) %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
<% color = balance_trend&.trend&.color || "#D444F1" %>
|
||||
<% icon = balance_trend&.trend&.icon || "plus" %>
|
||||
|
||||
<div class="p-4 grid grid-cols-12 items-center text-gray-900 text-sm font-medium">
|
||||
<div class="p-4 grid grid-cols-12 items-center text-primary text-sm font-medium">
|
||||
<div class="col-span-8 flex items-center gap-4">
|
||||
<% if selectable %>
|
||||
<%= check_box_tag dom_id(entry, "selection"),
|
||||
class: "maybe-checkbox maybe-checkbox--light",
|
||||
class: "checkbox checkbox--light",
|
||||
data: { id: entry.id, "bulk-select-target": "row", action: "bulk-select#toggleRowSelection" } %>
|
||||
<% end %>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
|||
<%= lucide_icon icon, class: "w-4 h-4 shrink-0" %>
|
||||
<% end %>
|
||||
|
||||
<div class="truncate text-gray-900">
|
||||
<div class="truncate text-primary">
|
||||
<% if entry.new_record? %>
|
||||
<%= content_tag :p, entry.display_name %>
|
||||
<% else %>
|
||||
|
@ -33,11 +33,11 @@
|
|||
<% if balance_trend&.trend %>
|
||||
<%= tag.span format_money(balance_trend.trend.value), style: "color: #{balance_trend.trend.color}" %>
|
||||
<% else %>
|
||||
<%= tag.span "--", class: "text-gray-400" %>
|
||||
<%= tag.span "--", class: "text-subdued" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 justify-self-end">
|
||||
<%= tag.p format_money(entry.amount_money), class: "font-medium text-sm text-gray-900" %>
|
||||
<%= tag.p format_money(entry.amount_money), class: "font-medium text-sm text-primary" %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
<%= tag.h2 t(".valuations"), class: "font-medium text-lg" %>
|
||||
<%= link_to new_account_valuation_path(@account),
|
||||
data: { turbo_frame: dom_id(@account.entries.account_valuations.new) },
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-gray-900 p-2 rounded-lg" do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-900") %>
|
||||
class: "flex gap-1 font-medium items-center bg-gray-50 text-primary p-2 rounded-lg" do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-primary") %>
|
||||
<%= tag.span t(".new_entry"), class: "text-sm" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="rounded-xl bg-gray-25 p-1">
|
||||
<div class="grid grid-cols-10 items-center uppercase text-xs font-medium text-gray-500 px-4 py-2">
|
||||
<div class="grid grid-cols-10 items-center uppercase text-xs font-medium text-secondary px-4 py-2">
|
||||
<%= tag.p t(".date"), class: "col-span-5" %>
|
||||
<%= tag.p t(".value"), class: "col-span-2 justify-self-end" %>
|
||||
<%= tag.p t(".change"), class: "col-span-2 justify-self-end" %>
|
||||
|
@ -27,7 +27,7 @@
|
|||
as: :entry,
|
||||
spacer_template: "account/entries/ruler" %>
|
||||
<% else %>
|
||||
<p class="text-gray-500 text-sm p-4"><%= t(".no_valuations") %></p>
|
||||
<p class="text-secondary text-sm p-4"><%= t(".no_valuations") %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -51,14 +51,14 @@
|
|||
<!-- Delete Valuation Form -->
|
||||
<div class="flex items-center justify-between gap-2 p-3">
|
||||
<div class="text-sm space-y-1">
|
||||
<h4 class="text-gray-900"><%= t(".delete_title") %></h4>
|
||||
<p class="text-gray-500"><%= t(".delete_subtitle") %></p>
|
||||
<h4 class="text-primary"><%= t(".delete_title") %></h4>
|
||||
<p class="text-secondary"><%= t(".delete_subtitle") %></p>
|
||||
</div>
|
||||
|
||||
<%= button_to t(".delete"),
|
||||
account_entry_path(entry),
|
||||
method: :delete,
|
||||
class: "rounded-lg px-3 py-2 text-red-500 text-sm font-medium border border-alpha-black-200",
|
||||
class: "rounded-lg px-3 py-2 text-red-500 text-sm font-medium border border-secondary",
|
||||
data: { turbo_confirm: true, turbo_frame: "_top" } %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<div>
|
||||
<% if account.scheduled_for_deletion? %>
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
<p class="text-sm font-medium text-primary">
|
||||
<span>
|
||||
<%= account.name %>
|
||||
</span>
|
||||
|
@ -16,7 +16,7 @@
|
|||
</span>
|
||||
</p>
|
||||
<% else %>
|
||||
<%= link_to account.name, account, class: [(account.is_active ? "text-gray-900" : "text-gray-400"), "text-sm font-medium hover:underline"], data: { turbo_frame: "_top" } %>
|
||||
<%= link_to account.name, account, class: [(account.is_active ? "text-primary" : "text-subdued"), "text-sm font-medium hover:underline"], data: { turbo_frame: "_top" } %>
|
||||
<% if account.has_issues? %>
|
||||
<div class="text-sm flex items-center gap-1 text-error">
|
||||
<%= lucide_icon "alert-octagon", class: "shrink-0 w-4 h-4" %>
|
||||
|
@ -29,12 +29,12 @@
|
|||
|
||||
<% unless account.scheduled_for_deletion? %>
|
||||
<%= link_to edit_account_path(account, return_to: return_to), data: { turbo_frame: :modal }, class: "group-hover/account:flex hidden hover:opacity-80 items-center justify-center" do %>
|
||||
<%= lucide_icon "pencil-line", class: "w-4 h-4 text-gray-500" %>
|
||||
<%= lucide_icon "pencil-line", class: "w-4 h-4 text-secondary" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex items-center gap-8">
|
||||
<p class="text-sm font-medium <%= account.is_active ? "text-gray-900" : "text-gray-400" %>">
|
||||
<p class="text-sm font-medium <%= account.is_active ? "text-primary" : "text-subdued" %>">
|
||||
<%= format_money account.balance_money %>
|
||||
</p>
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
|||
data: { controller: "auto-submit-form", turbo_frame: "_top" } do |form| %>
|
||||
<div class="relative inline-block select-none">
|
||||
<%= form.check_box :is_active, { class: "sr-only peer", data: { "auto-submit-form-target": "auto" } } %>
|
||||
<%= form.label :is_active, " ".html_safe, class: "maybe-switch" %>
|
||||
<%= form.label :is_active, " ".html_safe, class: "switch" %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<summary class="flex gap-4 px-3 py-2 items-center w-full rounded-[10px] font-medium
|
||||
hover:bg-gray-100 cursor-pointer">
|
||||
<%= lucide_icon("chevron-down",
|
||||
class: "hidden group-open:block text-gray-500 w-5 h-5") %>
|
||||
class: "hidden group-open:block text-secondary w-5 h-5") %>
|
||||
<%= lucide_icon("chevron-right",
|
||||
class: "group-open:hidden text-gray-500 w-5 h-5") %>
|
||||
class: "group-open:hidden text-secondary w-5 h-5") %>
|
||||
|
||||
<div class="text-left"><%= type.model_name.human %></div>
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
|||
<div class="overflow-hidden">
|
||||
<p class="font-medium truncate"><%= account_value_node.name %></p>
|
||||
<% if account.subtype %>
|
||||
<p class="text-xs text-gray-500"><%= account.subtype&.humanize %></p>
|
||||
<p class="text-xs text-secondary"><%= account.subtype&.humanize %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex flex-col items-end font-medium text-right ml-auto">
|
||||
|
@ -53,7 +53,7 @@
|
|||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<%= link_to new_polymorphic_path(type, step: "method_select"), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= link_to new_polymorphic_path(type, step: "method_select"), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-secondary text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
<%= t(".new_account", type: type.model_name.human.downcase) %>
|
||||
<% end %>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="h-10">
|
||||
</div>
|
||||
<div class="h-64 flex items-center justify-center">
|
||||
<p class="text-gray-500 animate-pulse text-sm">Loading...</p>
|
||||
<p class="text-secondary animate-pulse text-sm">Loading...</p>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="flex justify-center items-center h-[800px] text-sm">
|
||||
<div class="text-center flex flex-col items-center max-w-[300px]">
|
||||
<%= tag.p t(".no_accounts"), class: "text-gray-900 mb-1 font-medium" %>
|
||||
<%= tag.p t(".empty_message"), class: "text-gray-500 mb-4" %>
|
||||
<%= tag.p t(".no_accounts"), class: "text-primary mb-1 font-medium" %>
|
||||
<%= tag.p t(".empty_message"), class: "text-secondary mb-4" %>
|
||||
|
||||
<%= link_to new_account_path, class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5") %>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<%# locals: (title:, content:) %>
|
||||
|
||||
<div class="rounded-xl bg-white shadow-xs border border-alpha-black-25 p-4">
|
||||
<h4 class="text-gray-500 text-sm"><%= title %></h4>
|
||||
<p class="text-xl font-medium text-gray-900">
|
||||
<h4 class="text-secondary text-sm"><%= title %></h4>
|
||||
<p class="text-xl font-medium text-primary">
|
||||
<%= content %>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<%= turbo_frame_tag dom_id(@account, :chart_details) do %>
|
||||
<div class="px-4">
|
||||
<% if trend.direction.flat? %>
|
||||
<%= tag.span t(".no_change"), class: "text-gray-500" %>
|
||||
<%= tag.span t(".no_change"), class: "text-secondary" %>
|
||||
<% else %>
|
||||
<%= tag.span "#{trend.value.positive? ? "+" : ""}#{format_money(trend.value)}", style: "color: #{trend.color}" %>
|
||||
<% unless trend.percent.infinite? %>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= tag.span period_label(period), class: "text-gray-500" %>
|
||||
<%= tag.span period_label(period), class: "text-secondary" %>
|
||||
</div>
|
||||
|
||||
<div class="h-64">
|
||||
|
@ -25,11 +25,11 @@
|
|||
data-time-series-chart-data-value="<%= series.to_json %>"></div>
|
||||
<% elsif series.empty? %>
|
||||
<div class="w-full h-full flex items-center justify-center">
|
||||
<p class="text-gray-500 text-sm">No data available for the selected period.</p>
|
||||
<p class="text-secondary text-sm">No data available for the selected period.</p>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="w-full h-full flex items-center justify-center">
|
||||
<p class="text-gray-500 text-sm animate-pulse">Calculating latest balance data...</p>
|
||||
<p class="text-secondary text-sm animate-pulse">Calculating latest balance data...</p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<% end %>
|
||||
|
||||
<div class="space-y-4">
|
||||
<header class="flex justify-between items-center text-gray-900 font-medium">
|
||||
<header class="flex justify-between items-center text-primary font-medium">
|
||||
<h1 class="text-xl"><%= t(".accounts") %></h1>
|
||||
<div class="flex items-center gap-5">
|
||||
<div class="flex items-center gap-2">
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
<% accounts.group_by(&:accountable_type).sort_by { |group, _| group }.each do |group, accounts| %>
|
||||
<div class="bg-gray-25 p-1 rounded-xl">
|
||||
<div class="flex items-center px-4 py-2 text-xs font-medium text-gray-500">
|
||||
<div class="flex items-center px-4 py-2 text-xs font-medium text-secondary">
|
||||
<p><%= to_accountable_title(Accountable.from_type(group)) %></p>
|
||||
<span class="text-gray-400 mx-2">·</span>
|
||||
<span class="text-subdued mx-2">·</span>
|
||||
<p><%= accounts.count %></p>
|
||||
<p class="ml-auto"><%= totals_by_currency(collection: accounts, money_method: :balance_money) %></p>
|
||||
</div>
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
<details open class="group bg-white p-4 border border-alpha-black-25 shadow-xs rounded-xl">
|
||||
<summary class="flex items-center gap-2 focus-visible:outline-hidden">
|
||||
<%= lucide_icon "chevron-right", class: "group-open:transform group-open:rotate-90 text-gray-500 w-5" %>
|
||||
<%= lucide_icon "chevron-right", class: "group-open:transform group-open:rotate-90 text-secondary w-5" %>
|
||||
|
||||
<div class="flex items-center justify-center h-8 w-8 rounded-full bg-black/5">
|
||||
<%= lucide_icon("folder-pen", class: "w-5 h-5 text-gray-500") %>
|
||||
<%= lucide_icon("folder-pen", class: "w-5 h-5 text-secondary") %>
|
||||
</div>
|
||||
|
||||
<span class="mr-auto text-sm font-medium text-gray-900"><%= t(".other_accounts") %></span>
|
||||
<span class="mr-auto text-sm font-medium text-primary"><%= t(".other_accounts") %></span>
|
||||
</summary>
|
||||
|
||||
<div class="space-y-4 mt-4">
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<div class="border-b border-alpha-black-25 p-4 text-gray-800 flex items-center space-x-3">
|
||||
<% if back_path %>
|
||||
<%= link_to back_path, class: "flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 focus:outline-gray-300 focus:outline" do %>
|
||||
<%= lucide_icon("arrow-left", class: "text-gray-500 w-5 h-5") %>
|
||||
<%= lucide_icon("arrow-left", class: "text-secondary w-5 h-5") %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<span class="text-gray-400"><%= title %></span>
|
||||
<span class="text-subdued"><%= title %></span>
|
||||
</div>
|
||||
|
||||
<div class="p-2">
|
||||
|
@ -19,7 +19,7 @@
|
|||
<%= yield %>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-alpha-black-25 p-4 text-gray-500 text-sm flex justify-between">
|
||||
<div class="border-t border-alpha-black-25 p-4 text-secondary text-sm flex justify-between">
|
||||
<div class="flex space-x-5">
|
||||
<div class="flex items-center space-x-2">
|
||||
<span>Select</span>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div class="text-sm">
|
||||
<%= link_to path, class: "flex items-center gap-4 w-full text-center focus:outline-hidden focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %>
|
||||
<span class="flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.02)]">
|
||||
<%= lucide_icon("keyboard", class: "text-gray-500 w-5 h-5") %>
|
||||
<%= lucide_icon("keyboard", class: "text-secondary w-5 h-5") %>
|
||||
</span>
|
||||
<%= t("accounts.new.method_selector.manual_entry") %>
|
||||
<% end %>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<%# Default US-only Link %>
|
||||
<button data-controller="plaid" data-action="plaid#open modal#close" data-plaid-region-value="us" data-plaid-link-token-value="<%= us_link_token %>" class="flex items-center gap-4 w-full text-center focus:outline-hidden focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2">
|
||||
<span class="flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.02)]">
|
||||
<%= lucide_icon("link-2", class: "text-gray-500 w-5 h-5") %>
|
||||
<%= lucide_icon("link-2", class: "text-secondary w-5 h-5") %>
|
||||
</span>
|
||||
<%= t("accounts.new.method_selector.connected_entry") %>
|
||||
</button>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<% if eu_link_token %>
|
||||
<button data-controller="plaid" data-action="plaid#open modal#close" data-plaid-region-value="eu" data-plaid-link-token-value="<%= eu_link_token %>" class="flex items-center gap-4 w-full text-center focus:outline-hidden focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2">
|
||||
<span class="flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.02)]">
|
||||
<%= lucide_icon("link-2", class: "text-gray-500 w-5 h-5") %>
|
||||
<%= lucide_icon("link-2", class: "text-secondary w-5 h-5") %>
|
||||
</span>
|
||||
<%= t("accounts.new.method_selector.connected_entry_eu") %>
|
||||
</button>
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
</button>
|
||||
<div data-menu-target="content" class="z-10 hidden bg-white rounded-lg border border-alpha-black-25 shadow-xs p-1">
|
||||
<%= link_to new_account_valuation_path(account_id: @account.id), data: { turbo_frame: :modal }, class: "block p-2 rounded-lg hover:bg-gray-50 flex items-center gap-2" do %>
|
||||
<%= lucide_icon("circle-dollar-sign", class: "text-gray-500 w-5 h-5") %>
|
||||
<%= lucide_icon("circle-dollar-sign", class: "text-secondary w-5 h-5") %>
|
||||
<%= tag.span t(".new_balance"), class: "text-sm" %>
|
||||
<% end %>
|
||||
|
||||
<% unless @account.crypto? %>
|
||||
<%= link_to @account.investment? ? new_account_trade_path(account_id: @account.id) : new_account_transaction_path(account_id: @account.id), data: { turbo_frame: :modal }, class: "block p-2 rounded-lg hover:bg-gray-50 flex items-center gap-2" do %>
|
||||
<%= lucide_icon("credit-card", class: "text-gray-500 w-5 h-5") %>
|
||||
<%= lucide_icon("credit-card", class: "text-secondary w-5 h-5") %>
|
||||
<%= tag.span t(".new_transaction"), class: "text-sm" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
@ -36,12 +36,12 @@
|
|||
<div class="flex gap-2 mb-4">
|
||||
<div class="grow">
|
||||
<div class="flex items-center px-3 py-2 gap-2 border border-gray-200 rounded-lg focus-within:ring-gray-100 focus-within:border-gray-900">
|
||||
<%= lucide_icon("search", class: "w-5 h-5 text-gray-500") %>
|
||||
<%= lucide_icon("search", class: "w-5 h-5 text-secondary") %>
|
||||
<%= hidden_field_tag :account_id, @account.id %>
|
||||
<%= form.search_field :search,
|
||||
placeholder: "Search entries by name",
|
||||
value: @q[:search],
|
||||
class: "form-field__input placeholder:text-sm placeholder:text-gray-500",
|
||||
class: "form-field__input placeholder:text-sm placeholder:text-secondary",
|
||||
"data-auto-submit-form-target": "auto" %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -50,7 +50,7 @@
|
|||
</div>
|
||||
|
||||
<% if @entries.empty? %>
|
||||
<p class="text-gray-500 text-sm p-4"><%= t(".no_entries") %></p>
|
||||
<p class="text-secondary text-sm p-4"><%= t(".no_entries") %></p>
|
||||
<% else %>
|
||||
<%= tag.div id: dom_id(@account, "entries_bulk_select"),
|
||||
data: {
|
||||
|
@ -62,10 +62,10 @@
|
|||
<%= render "account/entries/selection_bar" %>
|
||||
</div>
|
||||
|
||||
<div class="grid bg-gray-25 rounded-xl grid-cols-12 items-center uppercase text-xs font-medium text-gray-500 px-5 py-3 mb-4">
|
||||
<div class="grid bg-gray-25 rounded-xl grid-cols-12 items-center uppercase text-xs font-medium text-secondary px-5 py-3 mb-4">
|
||||
<div class="pl-0.5 col-span-8 flex items-center gap-4">
|
||||
<%= check_box_tag "selection_entry",
|
||||
class: "maybe-checkbox maybe-checkbox--light",
|
||||
class: "checkbox checkbox--light",
|
||||
data: { action: "bulk-select#togglePageSelection" } %>
|
||||
<p><%= t(".date") %></p>
|
||||
</div>
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
<div class="flex justify-between px-4 pt-4 mb-2">
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-1">
|
||||
<%= tag.p title || default_value_title, class: "text-sm font-medium text-gray-500" %>
|
||||
<%= tag.p title || default_value_title, class: "text-sm font-medium text-secondary" %>
|
||||
<%= tooltip %>
|
||||
</div>
|
||||
|
||||
<%= tag.p format_money(account.balance_money), class: "text-gray-900 text-3xl font-medium" %>
|
||||
<%= tag.p format_money(account.balance_money), class: "text-primary text-3xl font-medium" %>
|
||||
</div>
|
||||
|
||||
<%= form_with url: request.path, method: :get, data: { controller: "auto-submit-form" } do |form| %>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<div class="truncate">
|
||||
<h2 class="font-medium text-xl truncate"><%= title || account.name %></h2>
|
||||
<% if subtitle.present? %>
|
||||
<p class="text-sm text-gray-500"><%= subtitle %></p>
|
||||
<p class="text-sm text-secondary"><%= subtitle %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,12 +23,12 @@
|
|||
<% if account.plaid_account_id.present? %>
|
||||
<% if Rails.env.development? %>
|
||||
<%= button_to sync_plaid_item_path(account.plaid_account.plaid_item), disabled: account.syncing?, data: { turbo: false }, class: "flex items-center gap-2", title: "Sync Account" do %>
|
||||
<%= lucide_icon "refresh-cw", class: "w-4 h-4 text-gray-500 hover:text-gray-400" %>
|
||||
<%= lucide_icon "refresh-cw", class: "w-4 h-4 text-secondary hover:text-subdued" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= button_to sync_account_path(account), disabled: account.syncing?, data: { turbo: false }, class: "flex items-center gap-2", title: "Sync Account" do %>
|
||||
<%= lucide_icon "refresh-cw", class: "w-4 h-4 text-gray-500 hover:text-gray-400" %>
|
||||
<%= lucide_icon "refresh-cw", class: "w-4 h-4 text-secondary hover:text-subdued" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<div class="p-5">
|
||||
<p class="text-gray-500 animate-pulse">Loading account...</p>
|
||||
<p class="text-secondary animate-pulse">Loading account...</p>
|
||||
</div>
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<%# locals: (account:) %>
|
||||
|
||||
<%= contextual_menu do %>
|
||||
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<div class="w-48 p-1 text-sm leading-6 text-primary bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<% if account.plaid_account_id.present? %>
|
||||
<%= link_to accounts_path,
|
||||
data: { turbo_frame: :_top },
|
||||
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
|
||||
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %>
|
||||
class: "block w-full py-2 px-3 space-x-2 text-primary hover:bg-gray-50 flex items-center rounded-lg" do %>
|
||||
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-secondary" %>
|
||||
|
||||
<span><%= t(".manage") %></span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= link_to edit_account_path(account),
|
||||
data: { turbo_frame: :modal },
|
||||
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
|
||||
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %>
|
||||
class: "block w-full py-2 px-3 space-x-2 text-primary hover:bg-gray-50 flex items-center rounded-lg" do %>
|
||||
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-secondary" %>
|
||||
|
||||
<span><%= t(".edit") %></span>
|
||||
<% end %>
|
||||
|
@ -22,8 +22,8 @@
|
|||
<% unless account.crypto? %>
|
||||
<%= link_to new_import_path,
|
||||
data: { turbo_frame: :modal },
|
||||
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %>
|
||||
<%= lucide_icon "download", class: "w-5 h-5 text-gray-500" %>
|
||||
class: "block w-full py-2 px-3 space-x-2 text-primary hover:bg-gray-50 flex items-center rounded-lg" do %>
|
||||
<%= lucide_icon "download", class: "w-5 h-5 text-secondary" %>
|
||||
|
||||
<span><%= t(".import") %></span>
|
||||
<% end %>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<% selected_tab = tabs.find { |tab| tab[:key] == params[:tab] } || tabs.first %>
|
||||
|
||||
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
|
||||
<div class="flex gap-2 text-sm text-primary font-medium mb-4">
|
||||
<% tabs.each do |tab| %>
|
||||
<%= render "accounts/show/tab", account: account, key: tab[:key], is_selected: selected_tab[:key] == tab[:key] %>
|
||||
<% end %>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<%= render "accounts/summary/header" %>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-xs border border-alpha-black-100 flex divide-x divide-gray-200">
|
||||
<div class="bg-white rounded-xl shadow-xs border border-tertiary flex divide-x divide-gray-200">
|
||||
<div class="w-1/2 p-4 flex items-stretch justify-between">
|
||||
<div class="space-y-2 grow">
|
||||
<%= render partial: "shared/value_heading", locals: {
|
||||
|
@ -41,10 +41,10 @@
|
|||
</div>
|
||||
<div class="p-4 bg-white rounded-xl shadow-xs border border-alpha-black-25 space-y-4">
|
||||
<div class="flex justify-between items-center mb-5">
|
||||
<h2 class="text-lg font-medium text-gray-900">Assets</h2>
|
||||
<h2 class="text-lg font-medium text-primary">Assets</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-secondary") %>
|
||||
<p><%= t(".new") %></p>
|
||||
<% end %>
|
||||
<%= form_with url: summary_accounts_path, method: :get, data: { controller: "auto-submit-form" } do |form| %>
|
||||
|
@ -58,18 +58,18 @@
|
|||
<%= render partial: "pages/account_percentages_table", locals: { account_groups: @account_groups[:assets].children } %>
|
||||
<% else %>
|
||||
<div class="py-20 flex flex-col items-center">
|
||||
<%= lucide_icon "blocks", class: "w-6 h-6 shrink-0 text-gray-500" %>
|
||||
<p class="text-gray-900 text-sm font-medium mb-1 mt-4"><%= t(".no_assets") %></p>
|
||||
<p class="text-gray-500 text-sm max-w-xs text-center"><%= t(".no_assets_description") %></p>
|
||||
<%= lucide_icon "blocks", class: "w-6 h-6 shrink-0 text-secondary" %>
|
||||
<p class="text-primary text-sm font-medium mb-1 mt-4"><%= t(".no_assets") %></p>
|
||||
<p class="text-secondary text-sm max-w-xs text-center"><%= t(".no_assets_description") %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="p-4 bg-white rounded-xl shadow-xs border border-alpha-black-25 space-y-4">
|
||||
<div class="flex justify-between items-center mb-5">
|
||||
<h2 class="text-lg font-medium text-gray-900">Liabilities</h2>
|
||||
<h2 class="text-lg font-medium text-primary">Liabilities</h2>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>
|
||||
<%= lucide_icon("plus", class: "w-5 h-5 text-secondary") %>
|
||||
<p><%= t(".new") %></p>
|
||||
<% end %>
|
||||
<%= form_with url: summary_accounts_path, method: :get, data: { controller: "auto-submit-form" } do |form| %>
|
||||
|
@ -83,9 +83,9 @@
|
|||
<%= render partial: "pages/account_percentages_table", locals: { account_groups: @account_groups[:liabilities].children } %>
|
||||
<% else %>
|
||||
<div class="py-20 flex flex-col items-center">
|
||||
<%= lucide_icon "scale", class: "w-6 h-6 shrink-0 text-gray-500" %>
|
||||
<p class="text-gray-900 text-sm font-medium mb-1 mt-4"><%= t(".no_liabilities") %></p>
|
||||
<p class="text-gray-500 text-sm max-w-xs text-center"><%= t(".no_liabilities_description") %></p>
|
||||
<%= lucide_icon "scale", class: "w-6 h-6 shrink-0 text-secondary" %>
|
||||
<p class="text-primary text-sm font-medium mb-1 mt-4"><%= t(".no_liabilities") %></p>
|
||||
<p class="text-secondary text-sm max-w-xs text-center"><%= t(".no_liabilities_description") %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<header class="flex justify-between items-center text-gray-900 font-medium">
|
||||
<header class="flex justify-between items-center text-primary font-medium">
|
||||
<h1 class="text-xl"><%= t(".accounts") %></h1>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= contextual_menu do %>
|
||||
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<div class="w-48 p-1 text-sm leading-6 text-primary bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<%= link_to accounts_path(return_to: summary_accounts_path),
|
||||
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg font-normal" do %>
|
||||
<%= lucide_icon "settings", class: "w-5 h-5 text-gray-500" %>
|
||||
class: "block w-full py-2 px-3 space-x-2 text-primary hover:bg-gray-50 flex items-center rounded-lg font-normal" do %>
|
||||
<%= lucide_icon "settings", class: "w-5 h-5 text-secondary" %>
|
||||
<span class="text-black"><%= t(".manage") %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<% if pagy.prev %>
|
||||
<%= link_to pagy_url_for(pagy, pagy.prev),
|
||||
data: { turbo_frame: :_top },
|
||||
class: "inline-flex items-center p-2 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" do %>
|
||||
<%= lucide_icon("chevron-left", class: "w-5 h-5 text-gray-500") %>
|
||||
class: "inline-flex items-center p-2 text-sm font-medium text-secondary hover:border-gray-300 hover:text-gray-700" do %>
|
||||
<%= lucide_icon("chevron-left", class: "w-5 h-5 text-secondary") %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="inline-flex items-center p-2 text-sm font-medium hover:border-gray-300">
|
||||
|
@ -20,17 +20,17 @@
|
|||
<% if series_item.is_a?(Integer) %>
|
||||
<%= link_to pagy_url_for(pagy, series_item),
|
||||
data: { turbo_frame: :_top },
|
||||
class: "rounded-md px-2 py-1 inline-flex items-center text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" do %>
|
||||
class: "rounded-md px-2 py-1 inline-flex items-center text-sm font-medium text-secondary hover:border-gray-300 hover:text-gray-700" do %>
|
||||
<%= series_item %>
|
||||
<% end %>
|
||||
<% elsif series_item.is_a?(String) %>
|
||||
<%= link_to pagy_url_for(pagy, series_item),
|
||||
data: { turbo_frame: :_top },
|
||||
class: "rounded-md px-2 py-1 bg-white border border-alpha-black-25 shadow-xs inline-flex items-center text-sm font-medium text-gray-900" do %>
|
||||
class: "rounded-md px-2 py-1 bg-white border border-alpha-black-25 shadow-xs inline-flex items-center text-sm font-medium text-primary" do %>
|
||||
<%= series_item %>
|
||||
<% end %>
|
||||
<% elsif series_item == :gap %>
|
||||
<span class="inline-flex items-center px-2 py-1 text-sm font-medium text-gray-500">...</span>
|
||||
<span class="inline-flex items-center px-2 py-1 text-sm font-medium text-secondary">...</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -38,8 +38,8 @@
|
|||
<% if pagy.next %>
|
||||
<%= link_to pagy_url_for(pagy, pagy.next),
|
||||
data: { turbo_frame: :_top },
|
||||
class: "inline-flex items-center p-2 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700" do %>
|
||||
<%= lucide_icon("chevron-right", class: "w-5 h-5 text-gray-500") %>
|
||||
class: "inline-flex items-center p-2 text-sm font-medium text-secondary hover:border-gray-300 hover:text-gray-700" do %>
|
||||
<%= lucide_icon("chevron-right", class: "w-5 h-5 text-secondary") %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="inline-flex items-center p-2 text-sm font-medium hover:border-gray-300">
|
||||
|
@ -52,6 +52,6 @@
|
|||
<%= select_tag :per_page,
|
||||
options_for_select(["10", "20", "30", "50"], pagy.limit),
|
||||
data: { controller: "selectable-link" },
|
||||
class: "py-1.5 pr-8 text-sm text-gray-900 font-medium border border-gray-200 rounded-lg focus:border-gray-900 focus:ring-gray-900 focus-visible:ring-gray-900" %>
|
||||
class: "py-1.5 pr-8 text-sm text-primary font-medium border border-gray-200 rounded-lg focus:border-gray-900 focus:ring-gray-900 focus-visible:ring-gray-900" %>
|
||||
</div>
|
||||
</nav>
|
||||
|
|
|
@ -9,17 +9,17 @@
|
|||
<% end %>
|
||||
|
||||
<% if budget.available_to_allocate.negative? %>
|
||||
<p class="text-gray-900 text-sm">> 100% set</p>
|
||||
<p class="text-primary text-sm">> 100% set</p>
|
||||
<% else %>
|
||||
<p class="text-gray-500 text-sm">
|
||||
<p class="text-secondary text-sm">
|
||||
<%= number_to_percentage(budget.allocated_percent, precision: 0) %> set
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<p class="ml-auto text-sm space-x-1">
|
||||
<span class="<%= budget.available_to_allocate.negative? ? "text-red-500" : "text-gray-900" %>"><%= format_money(budget.allocated_spending_money) %></span>
|
||||
<span class="text-gray-500"> / </span>
|
||||
<span class="text-gray-500"><%= format_money(budget.budgeted_spending_money) %></span>
|
||||
<span class="<%= budget.available_to_allocate.negative? ? "text-red-500" : "text-primary" %>"><%= format_money(budget.allocated_spending_money) %></span>
|
||||
<span class="text-secondary"> / </span>
|
||||
<span class="text-secondary"><%= format_money(budget.budgeted_spending_money) %></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -33,12 +33,12 @@
|
|||
|
||||
<div class="text-sm">
|
||||
<% if budget.available_to_allocate.negative? %>
|
||||
<p class="text-gray-500">
|
||||
<p class="text-secondary">
|
||||
Budget exceeded by <span class="text-red-500"><%= format_money(budget.available_to_allocate_money.abs) %></span>
|
||||
</p>
|
||||
<% else %>
|
||||
<span class="text-gray-900"><%= format_money(budget.available_to_allocate_money) %></span>
|
||||
<span class="text-gray-500">left to allocate</span>
|
||||
<span class="text-primary"><%= format_money(budget.available_to_allocate_money) %></span>
|
||||
<span class="text-secondary">left to allocate</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -18,30 +18,30 @@
|
|||
<% end %>
|
||||
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-900"><%= budget_category.category.name %></p>
|
||||
<p class="text-sm font-medium text-primary"><%= budget_category.category.name %></p>
|
||||
|
||||
<% if budget_category.initialized? %>
|
||||
<% if budget_category.available_to_spend.negative? %>
|
||||
<p class="text-sm font-medium text-red-500"><%= format_money(budget_category.available_to_spend_money.abs) %> over</p>
|
||||
<% elsif budget_category.available_to_spend.zero? %>
|
||||
<p class="text-sm font-medium <%= budget_category.budgeted_spending.positive? ? "text-orange-500" : "text-gray-500" %>">
|
||||
<p class="text-sm font-medium <%= budget_category.budgeted_spending.positive? ? "text-orange-500" : "text-secondary" %>">
|
||||
<%= format_money(budget_category.available_to_spend_money) %> left
|
||||
</p>
|
||||
<% else %>
|
||||
<p class="text-sm text-gray-500 font-medium"><%= format_money(budget_category.available_to_spend_money) %> left</p>
|
||||
<p class="text-sm text-secondary font-medium"><%= format_money(budget_category.available_to_spend_money) %> left</p>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<p class="text-sm text-gray-500 font-medium">
|
||||
<p class="text-sm text-secondary font-medium">
|
||||
<%= format_money(budget_category.category.avg_monthly_total_money, precision: 0) %> avg
|
||||
</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto text-right">
|
||||
<p class="text-sm font-medium text-gray-900"><%= format_money(budget_category.actual_spending_money) %></p>
|
||||
<p class="text-sm font-medium text-primary"><%= format_money(budget_category.actual_spending_money) %></p>
|
||||
|
||||
<% if budget_category.initialized? %>
|
||||
<p class="text-sm text-gray-500">from <%= format_money(budget_category.budgeted_spending_money) %></p>
|
||||
<p class="text-sm text-secondary">from <%= format_money(budget_category.budgeted_spending_money) %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -6,16 +6,16 @@
|
|||
<div class="w-1 h-3 rounded-xl mt-1" style="background-color: <%= budget_category.category.color %>"></div>
|
||||
|
||||
<div class="text-sm mr-3">
|
||||
<p class="text-gray-900 font-medium mb-0.5"><%= budget_category.category.name %></p>
|
||||
<p class="text-primary font-medium mb-0.5"><%= budget_category.category.name %></p>
|
||||
|
||||
<p class="text-gray-500"><%= format_money(budget_category.category.avg_monthly_total_money, precision: 0) %>/m average</p>
|
||||
<p class="text-secondary"><%= format_money(budget_category.category.avg_monthly_total_money, precision: 0) %>/m average</p>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto">
|
||||
<%= form_with model: [budget_category.budget, budget_category], data: { controller: "auto-submit-form preserve-focus" } do |f| %>
|
||||
<div class="form-field w-[120px]">
|
||||
<div class="flex items-center">
|
||||
<span class="text-gray-500 text-sm mr-2"><%= currency.symbol %></span>
|
||||
<span class="text-secondary text-sm mr-2"><%= currency.symbol %></span>
|
||||
<%= f.number_field :budgeted_spending,
|
||||
class: "form-field__input text-right [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none",
|
||||
placeholder: "0",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
budget_path(budget),
|
||||
class: "block btn btn--primary w-full text-center" %>
|
||||
<% else %>
|
||||
<span class="block btn btn--secondary w-full text-center text-gray-400 cursor-not-allowed">
|
||||
<span class="block btn btn--secondary w-full text-center text-subdued cursor-not-allowed">
|
||||
Confirm
|
||||
</span>
|
||||
<% end %>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<div class="flex justify-center items-center">
|
||||
<div class="text-center flex flex-col items-center max-w-[500px]">
|
||||
<h2 class="text-lg text-gray-900 font-medium">Oops!</h2>
|
||||
<p class="text-gray-500 text-sm max-w-sm mx-auto mb-4">
|
||||
<h2 class="text-lg text-primary font-medium">Oops!</h2>
|
||||
<p class="text-secondary text-sm max-w-sm mx-auto mb-4">
|
||||
You have not created or assigned any expense categories to your transactions yet.
|
||||
</p>
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
<div class="w-1 h-3 rounded-xl mt-1" style="background-color: <%= budget_category.category.color %>"></div>
|
||||
|
||||
<div class="text-sm mr-3">
|
||||
<p class="text-gray-900 font-medium mb-0.5"><%= budget_category.category.name %></p>
|
||||
<p class="text-gray-500"><%= format_money(Money.new(budget_category.category.avg_monthly_total, budget_category.category.family.currency), precision: 0) %>/m average</p>
|
||||
<p class="text-primary font-medium mb-0.5"><%= budget_category.category.name %></p>
|
||||
<p class="text-secondary"><%= format_money(Money.new(budget_category.category.avg_monthly_total, budget_category.category.family.currency), precision: 0) %>/m average</p>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto">
|
||||
<div class="form-field w-[120px]">
|
||||
<div class="flex items-center">
|
||||
<span class="text-gray-400 text-sm mr-2">$</span>
|
||||
<span class="text-subdued text-sm mr-2">$</span>
|
||||
<%= text_field_tag :uncategorized, budget_category.budgeted_spending_money, autocomplete: "off", class: "form-field__input text-right [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none", disabled: true %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<div>
|
||||
<div class="space-y-6">
|
||||
<div class="text-center space-y-2">
|
||||
<h1 class="text-3xl text-gray-900 font-medium">Edit your category budgets</h1>
|
||||
<p class="text-gray-500 text-sm max-w-md mx-auto">
|
||||
<h1 class="text-3xl text-primary font-medium">Edit your category budgets</h1>
|
||||
<p class="text-secondary text-sm max-w-md mx-auto">
|
||||
Adjust category budgets to set spending limits. Unallocated funds will be automatically assigned as uncategorized.
|
||||
</p>
|
||||
</div>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<div class="space-y-4">
|
||||
<% group.budget_subcategories.each do |budget_subcategory| %>
|
||||
<div class="w-full flex items-center gap-4">
|
||||
<div class="ml-4 flex items-center justify-center text-gray-400">
|
||||
<div class="ml-4 flex items-center justify-center text-subdued">
|
||||
<%= lucide_icon "corner-down-right", class: "w-5 h-5 shrink-0" %>
|
||||
</div>
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
|||
<%= render "budget_categories/uncategorized_budget_category_form", budget: @budget %>
|
||||
</div>
|
||||
|
||||
<%= render "budget_categories/confirm_button", budget: @budget %>
|
||||
<%= render "budget_categories/confirm_button", budget: @budget %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
<div class="space-y-4">
|
||||
<header class="flex justify-between">
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Category</p>
|
||||
<h3 class="text-2xl font-medium text-gray-900">
|
||||
<p class="text-sm text-secondary">Category</p>
|
||||
<h3 class="text-2xl font-medium text-primary">
|
||||
<%= @budget_category.category.name %>
|
||||
</h3>
|
||||
|
||||
<% if @budget_category.budget.initialized? %>
|
||||
<p class="text-sm text-gray-500">
|
||||
<span class="text-gray-900">
|
||||
<p class="text-sm text-secondary">
|
||||
<span class="text-primary">
|
||||
<%= format_money(@budget_category.actual_spending_money) %>
|
||||
</span>
|
||||
<span>/</span>
|
||||
|
@ -28,26 +28,26 @@
|
|||
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2
|
||||
text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4>Overview</h4>
|
||||
<%= lucide_icon "chevron-down",
|
||||
class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="pb-4">
|
||||
<dl class="space-y-3 px-3 py-2">
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500">
|
||||
<dt class="text-secondary">
|
||||
<%= @budget_category.budget.start_date.strftime("%b %Y") %> spending
|
||||
</dt>
|
||||
<dd class="text-gray-900 font-medium">
|
||||
<dd class="text-primary font-medium">
|
||||
<%= format_money @budget_category.actual_spending_money %>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<% if @budget_category.budget.initialized? %>
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500">Status</dt>
|
||||
<dt class="text-secondary">Status</dt>
|
||||
<% if @budget_category.available_to_spend.negative? %>
|
||||
<dd class="text-red-500 flex items-center gap-1 text-red-500 font-medium">
|
||||
<%= lucide_icon "alert-circle", class: "shrink-0 w-4 h-4 text-red-500" %>
|
||||
|
@ -61,7 +61,7 @@
|
|||
<span>left</span>
|
||||
</dd>
|
||||
<% else %>
|
||||
<dd class="text-gray-900 flex items-center gap-1 text-green-500 font-medium">
|
||||
<dd class="text-primary flex items-center gap-1 text-green-500 font-medium">
|
||||
<%= lucide_icon "check-circle-2", class: "shrink-0 w-4 h-4 text-green-500" %>
|
||||
<%= format_money @budget_category.available_to_spend_money %>
|
||||
<span>left</span>
|
||||
|
@ -70,23 +70,23 @@
|
|||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500">Budgeted</dt>
|
||||
<dd class="text-gray-900 font-medium">
|
||||
<dt class="text-secondary">Budgeted</dt>
|
||||
<dd class="text-primary font-medium">
|
||||
<%= format_money @budget_category.budgeted_spending_money %>
|
||||
</dd>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500">Monthly average spending</dt>
|
||||
<dd class="text-gray-900 font-medium">
|
||||
<dt class="text-secondary">Monthly average spending</dt>
|
||||
<dd class="text-primary font-medium">
|
||||
<%= format_money @budget_category.category.avg_monthly_total_money, precision: 0 %>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between text-sm">
|
||||
<dt class="text-gray-500">Monthly median spending</dt>
|
||||
<dd class="text-gray-900 font-medium">
|
||||
<dt class="text-secondary">Monthly median spending</dt>
|
||||
<dd class="text-primary font-medium">
|
||||
<%= format_money @budget_category.category.median_monthly_total_money, precision: 0 %>
|
||||
</dd>
|
||||
</div>
|
||||
|
@ -96,10 +96,10 @@
|
|||
|
||||
<details class="group space-y-2" open>
|
||||
<summary class="flex list-none items-center justify-between rounded-xl px-3 py-2
|
||||
text-xs font-medium uppercase text-gray-500 bg-gray-25 focus-visible:outline-hidden">
|
||||
text-xs font-medium uppercase text-secondary bg-gray-25 focus-visible:outline-hidden">
|
||||
<h4>Recent Transactions</h4>
|
||||
<%= lucide_icon "chevron-down",
|
||||
class: "group-open:transform group-open:rotate-180 text-gray-500 w-5" %>
|
||||
class: "group-open:transform group-open:rotate-180 text-secondary w-5" %>
|
||||
</summary>
|
||||
|
||||
<div class="space-y-2">
|
||||
|
@ -117,12 +117,12 @@
|
|||
|
||||
<div class="flex justify-between w-full">
|
||||
<div>
|
||||
<p class="text-gray-500 text-xs uppercase">
|
||||
<p class="text-secondary text-xs uppercase">
|
||||
<%= entry.date.strftime("%b %d") %>
|
||||
</p>
|
||||
<p class="text-gray-900"><%= entry.name %></p>
|
||||
<p class="text-primary"><%= entry.name %></p>
|
||||
</div>
|
||||
<p class="text-gray-900 font-medium">
|
||||
<p class="text-primary font-medium">
|
||||
<%= format_money entry.amount_money %>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -139,7 +139,7 @@
|
|||
data: { turbo_frame: :_top },
|
||||
class: "block text-center btn btn--outline w-full" %>
|
||||
<% else %>
|
||||
<p class="text-gray-500 text-sm mb-4">
|
||||
<p class="text-secondary text-sm mb-4">
|
||||
No transactions found for this budget period.
|
||||
</p>
|
||||
<% end %>
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
<div>
|
||||
<div class="p-4 border-b border-gray-100">
|
||||
<h3 class="text-sm text-gray-500 mb-2">Income</h3>
|
||||
<h3 class="text-sm text-secondary mb-2">Income</h3>
|
||||
|
||||
<% income_totals = budget.income_categories_with_totals %>
|
||||
<% income_categories = income_totals.category_totals.reject { |ct| ct.amount_money.zero? }.sort_by { |ct| ct.percentage }.reverse %>
|
||||
<span class="inline-block mb-2 text-xl font-medium text-gray-900">
|
||||
<span class="inline-block mb-2 text-xl font-medium text-primary">
|
||||
<%= format_money(income_totals.total_money) %>
|
||||
</span>
|
||||
|
||||
|
@ -22,8 +22,8 @@
|
|||
<% income_categories.each do |item| %>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="w-2.5 h-2.5 rounded-full shrink-0" style="background-color: <%= item.category.color %>"></div>
|
||||
<span class="text-gray-500"><%= item.category.name %></span>
|
||||
<span class="text-gray-900"><%= number_to_percentage(item.percentage, precision: 0) %></span>
|
||||
<span class="text-secondary"><%= item.category.name %></span>
|
||||
<span class="text-primary"><%= number_to_percentage(item.percentage, precision: 0) %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -32,12 +32,12 @@
|
|||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<h3 class="text-sm text-gray-500 mb-2">Expenses</h3>
|
||||
<h3 class="text-sm text-secondary mb-2">Expenses</h3>
|
||||
|
||||
<% expense_totals = budget.expense_categories_with_totals %>
|
||||
<% expense_categories = expense_totals.category_totals.reject { |ct| ct.amount_money.zero? || ct.category.subcategory? }.sort_by { |ct| ct.percentage }.reverse %>
|
||||
|
||||
<span class="inline-block mb-2 text-xl font-medium text-gray-900"><%= format_money(expense_totals.total_money) %></span>
|
||||
<span class="inline-block mb-2 text-xl font-medium text-primary"><%= format_money(expense_totals.total_money) %></span>
|
||||
|
||||
<% if expense_categories.any? %>
|
||||
<div>
|
||||
|
@ -51,8 +51,8 @@
|
|||
<% expense_categories.each do |item| %>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<div class="w-2.5 h-2.5 rounded-full shrink-0" style="background-color: <%= item.category.color %>"></div>
|
||||
<span class="text-gray-500"><%= item.category.name %></span>
|
||||
<span class="text-gray-900"><%= number_to_percentage(item.percentage, precision: 0) %></span>
|
||||
<span class="text-secondary"><%= item.category.name %></span>
|
||||
<span class="text-primary"><%= number_to_percentage(item.percentage, precision: 0) %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<%# locals: (budget:) %>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center gap-1.5 px-4 py-2 text-xs font-medium text-gray-500 uppercase">
|
||||
<div class="flex items-center gap-1.5 px-4 py-2 text-xs font-medium text-secondary uppercase">
|
||||
<p>Categories</p>
|
||||
<span class="text-gray-400">·</span>
|
||||
<span class="text-subdued">·</span>
|
||||
<p><%= budget.budget_categories.count %></p>
|
||||
|
||||
<p class="ml-auto">Amount</p>
|
||||
|
@ -24,7 +24,7 @@
|
|||
<div>
|
||||
<% group.budget_subcategories.each do |budget_subcategory| %>
|
||||
<div class="w-full flex items-center -mt-4">
|
||||
<div class="ml-8 flex items-center justify-center text-gray-400">
|
||||
<div class="ml-8 flex items-center justify-center text-subdued">
|
||||
<%= lucide_icon "corner-down-right", class: "w-5 h-5 shrink-0" %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -8,18 +8,18 @@
|
|||
<span>Spent</span>
|
||||
</div>
|
||||
|
||||
<div class="text-3xl font-medium <%= budget.available_to_spend.negative? ? "text-red-500" : "text-gray-900" %>">
|
||||
<div class="text-3xl font-medium <%= budget.available_to_spend.negative? ? "text-red-500" : "text-primary" %>">
|
||||
<%= format_money(budget.actual_spending_money) %>
|
||||
</div>
|
||||
|
||||
<%= link_to edit_budget_path(budget), class: "btn btn--secondary flex items-center gap-1 mt-2" do %>
|
||||
<span class="text-gray-900 font-medium">
|
||||
<span class="text-primary font-medium">
|
||||
of <%= format_money(budget.budgeted_spending_money) %>
|
||||
</span>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-gray-500 hover:text-gray-600" %>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-secondary hover:text-gray-600" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="text-gray-400 text-3xl mb-2">
|
||||
<div class="text-subdued text-3xl mb-2">
|
||||
<span><%= format_money Money.new(0, budget.currency || budget.family.currency) %></span>
|
||||
</div>
|
||||
<%= link_to edit_budget_path(budget), class: "flex items-center gap-2 btn btn--primary" do %>
|
||||
|
@ -34,26 +34,26 @@
|
|||
<div class="flex flex-col gap-2 items-center">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-1 h-3 rounded-xl" style="background-color: <%= bc.category.color %>"></div>
|
||||
<p class="text-sm text-gray-500"><%= bc.category.name %></p>
|
||||
<p class="text-sm text-secondary"><%= bc.category.name %></p>
|
||||
</div>
|
||||
|
||||
<p class="text-3xl font-medium <%= bc.available_to_spend.negative? ? "text-red-500" : "text-gray-900" %>">
|
||||
<p class="text-3xl font-medium <%= bc.available_to_spend.negative? ? "text-red-500" : "text-primary" %>">
|
||||
<%= format_money(bc.actual_spending_money) %>
|
||||
</p>
|
||||
|
||||
<%= link_to budget_budget_categories_path(budget), class: "btn btn--secondary flex items-center gap-1" do %>
|
||||
<span>of <%= format_money(bc.budgeted_spending_money, precision: 0) %></span>
|
||||
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-gray-500 shrink-0" %>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-secondary shrink-0" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div id="segment_unused" class="hidden">
|
||||
<p class="text-sm text-gray-500 text-center mb-2">Unused</p>
|
||||
<p class="text-sm text-secondary text-center mb-2">Unused</p>
|
||||
|
||||
<p class="text-3xl font-medium text-gray-900">
|
||||
<p class="text-3xl font-medium text-primary">
|
||||
<%= format_money(budget.available_to_spend_money) %>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<%= lucide_icon "chevron-left" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= lucide_icon "chevron-left", class: "text-gray-400" %>
|
||||
<%= lucide_icon "chevron-left", class: "text-subdued" %>
|
||||
<% end %>
|
||||
|
||||
<% if @next_budget %>
|
||||
|
@ -15,14 +15,14 @@
|
|||
<%= lucide_icon "chevron-right" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= lucide_icon "chevron-right", class: "text-gray-400" %>
|
||||
<%= lucide_icon "chevron-right", class: "text-subdued" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div data-controller="menu" data-menu-placement-value="bottom-start">
|
||||
<%= tag.button data: { menu_target: "button" }, class: "flex items-center gap-1 hover:bg-gray-50 rounded-md p-2" do %>
|
||||
<span class="text-gray-900 font-medium"><%= @budget.name %></span>
|
||||
<%= lucide_icon "chevron-down", class: "w-5 h-5 shrink-0 text-gray-500" %>
|
||||
<span class="text-primary font-medium"><%= @budget.name %></span>
|
||||
<%= lucide_icon "chevron-down", class: "w-5 h-5 shrink-0 text-secondary" %>
|
||||
<% end %>
|
||||
|
||||
<div data-menu-target="content" class="hidden z-10">
|
||||
|
@ -32,7 +32,7 @@
|
|||
|
||||
<div class="ml-auto">
|
||||
<% if @budget.current? %>
|
||||
<span class="border border-alpha-black-200 text-gray-900 text-sm font-medium px-3 py-2 rounded-lg">Today</span>
|
||||
<span class="border border-secondary text-primary text-sm font-medium px-3 py-2 rounded-lg">Today</span>
|
||||
<% else %>
|
||||
<%= link_to "Today", budget_path(@latest_budget), class: "btn btn--outline" %>
|
||||
<% end %>
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
<% is_current = request.path == step[:path] %>
|
||||
|
||||
<% text_class = if is_current
|
||||
"text-gray-900"
|
||||
"text-primary"
|
||||
else
|
||||
step[:is_complete] ? "text-green-600" : "text-gray-500"
|
||||
step[:is_complete] ? "text-green-600" : "text-secondary"
|
||||
end %>
|
||||
<% step_class = if is_current
|
||||
"bg-gray-900 text-white"
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
<div>
|
||||
<div class="p-4 border-b border-gray-100">
|
||||
<h3 class="text-sm text-gray-500 mb-2">Expected income</h3>
|
||||
<h3 class="text-sm text-secondary mb-2">Expected income</h3>
|
||||
|
||||
<span class="inline-block mb-2 text-xl font-medium text-gray-900">
|
||||
<span class="inline-block mb-2 text-xl font-medium text-primary">
|
||||
<%= format_money(budget.expected_income_money) %>
|
||||
</span>
|
||||
|
||||
|
@ -19,12 +19,12 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<p class="text-gray-500"><%= format_money(budget.actual_income_money) %> earned</p>
|
||||
<p class="text-secondary"><%= format_money(budget.actual_income_money) %> earned</p>
|
||||
<p class="font-medium">
|
||||
<% if budget.remaining_expected_income.negative? %>
|
||||
<span class="text-green-500"><%= format_money(budget.remaining_expected_income_money.abs) %> over</span>
|
||||
<% else %>
|
||||
<span class="text-gray-900"><%= format_money(budget.remaining_expected_income_money) %> left</span>
|
||||
<span class="text-primary"><%= format_money(budget.remaining_expected_income_money) %> left</span>
|
||||
<% end %>
|
||||
</p>
|
||||
</div>
|
||||
|
@ -32,9 +32,9 @@
|
|||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<h3 class="text-sm text-gray-500 mb-2">Budgeted</h3>
|
||||
<h3 class="text-sm text-secondary mb-2">Budgeted</h3>
|
||||
|
||||
<span class="inline-block mb-2 text-xl font-medium text-gray-900">
|
||||
<span class="inline-block mb-2 text-xl font-medium text-primary">
|
||||
<%= format_money(budget.budgeted_spending_money) %>
|
||||
</span>
|
||||
|
||||
|
@ -49,12 +49,12 @@
|
|||
<% end %>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<p class="text-gray-500"><%= format_money(budget.actual_spending_money) %> spent</p>
|
||||
<p class="text-secondary"><%= format_money(budget.actual_spending_money) %> spent</p>
|
||||
<p class="font-medium">
|
||||
<% if budget.available_to_spend.negative? %>
|
||||
<span class="text-red-500"><%= format_money(budget.available_to_spend_money.abs) %> over</span>
|
||||
<% else %>
|
||||
<span class="text-gray-900"><%= format_money(budget.available_to_spend_money) %> left</span>
|
||||
<span class="text-primary"><%= format_money(budget.available_to_spend_money) %> left</span>
|
||||
<% end %>
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
<div class="flex flex-col gap-4 items-center justify-center h-full">
|
||||
<%= lucide_icon "alert-triangle", class: "w-6 h-6 text-red-500" %>
|
||||
<p class="text-gray-500 text-sm text-center">You have over-allocated your budget. Please fix your allocations.</p>
|
||||
<p class="text-secondary text-sm text-center">You have over-allocated your budget. Please fix your allocations.</p>
|
||||
|
||||
<%= link_to budget_budget_categories_path(budget), class: "btn btn--secondary flex items-center gap-1" do %>
|
||||
<span class="text-gray-900 font-medium">
|
||||
<span class="text-primary font-medium">
|
||||
Fix allocations
|
||||
</span>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-gray-500 hover:text-gray-600" %>
|
||||
<%= lucide_icon "pencil", class: "w-4 h-4 text-secondary hover:text-gray-600" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -5,25 +5,25 @@
|
|||
<div class="flex items-center gap-2 justify-between">
|
||||
<% if year > family.oldest_entry_date.year %>
|
||||
<%= link_to picker_budgets_path(year: year - 1), data: { turbo_frame: "budget_picker" }, class: "p-2 flex items-center justify-center hover:bg-alpha-black-25 rounded-md" do %>
|
||||
<%= lucide_icon "chevron-left", class: "w-5 h-5 shrink-0 text-gray-500" %>
|
||||
<%= lucide_icon "chevron-left", class: "w-5 h-5 shrink-0 text-secondary" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="p-2 flex items-center justify-center text-gray-300 rounded-md">
|
||||
<%= lucide_icon "chevron-left", class: "w-5 h-5 shrink-0 text-gray-400" %>
|
||||
<%= lucide_icon "chevron-left", class: "w-5 h-5 shrink-0 text-subdued" %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<span class="w-40 text-center px-3 py-2 border border-alpha-black-100 rounded-md" data-budget-picker-target="year">
|
||||
<span class="w-40 text-center px-3 py-2 border border-tertiary rounded-md" data-budget-picker-target="year">
|
||||
<%= year %>
|
||||
</span>
|
||||
|
||||
<% if year < Date.current.year %>
|
||||
<%= link_to picker_budgets_path(year: year + 1), data: { turbo_frame: "budget_picker" }, class: "p-2 flex items-center justify-center hover:bg-alpha-black-25 rounded-md" do %>
|
||||
<%= lucide_icon "chevron-right", class: "w-5 h-5 shrink-0 text-gray-500" %>
|
||||
<%= lucide_icon "chevron-right", class: "w-5 h-5 shrink-0 text-secondary" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="p-2 flex items-center justify-center text-gray-300 rounded-md">
|
||||
<%= lucide_icon "chevron-right", class: "w-5 h-5 shrink-0 text-gray-400" %>
|
||||
<%= lucide_icon "chevron-right", class: "w-5 h-5 shrink-0 text-subdued" %>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -35,13 +35,13 @@
|
|||
<% budget = family.budgets.for_date(start_date) %>
|
||||
|
||||
<% if budget %>
|
||||
<%= link_to month_name, budget_path(budget), data: { turbo_frame: "_top" }, class: "block px-3 py-2 text-sm text-gray-900 hover:bg-gray-100 rounded-md" %>
|
||||
<%= link_to month_name, budget_path(budget), data: { turbo_frame: "_top" }, class: "block px-3 py-2 text-sm text-primary hover:bg-gray-100 rounded-md" %>
|
||||
<% elsif start_date >= family.oldest_entry_date.beginning_of_month && start_date <= Date.current %>
|
||||
<%= button_to budgets_path(budget: { start_date: start_date }), data: { turbo_frame: "_top" }, class: "block w-full px-3 py-2 text-gray-900 hover:bg-gray-100 rounded-md" do %>
|
||||
<%= button_to budgets_path(budget: { start_date: start_date }), data: { turbo_frame: "_top" }, class: "block w-full px-3 py-2 text-primary hover:bg-gray-100 rounded-md" do %>
|
||||
<%= month_name %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="px-3 py-2 text-gray-400 rounded-md"><%= month_name %></span>
|
||||
<span class="px-3 py-2 text-subdued rounded-md"><%= month_name %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<div>
|
||||
<div class="space-y-4">
|
||||
<div class="text-center space-y-2">
|
||||
<h1 class="text-3xl text-gray-900 font-medium">Setup your budget</h1>
|
||||
<p class="text-gray-500 text-sm max-w-sm mx-auto">
|
||||
<h1 class="text-3xl text-primary font-medium">Setup your budget</h1>
|
||||
<p class="text-secondary text-sm max-w-sm mx-auto">
|
||||
Enter your monthly earnings and planned spending below to setup your budget.
|
||||
</p>
|
||||
</div>
|
||||
|
@ -20,11 +20,11 @@
|
|||
<%= f.money_field :expected_income, label: "Expected income", required: true, disable_currency: true %>
|
||||
|
||||
<% if @budget.estimated_income && @budget.estimated_spending %>
|
||||
<div class="border border-alpha-black-100 rounded-lg p-3 flex">
|
||||
<%= lucide_icon "sparkles", class: "w-5 h-5 text-gray-500 shrink-0" %>
|
||||
<div class="border border-tertiary rounded-lg p-3 flex">
|
||||
<%= lucide_icon "sparkles", class: "w-5 h-5 text-secondary shrink-0" %>
|
||||
<div class="ml-2 space-y-1 text-sm">
|
||||
<h4 class="text-gray-900">Autosuggest income & spending budget</h4>
|
||||
<p class="text-gray-500">
|
||||
<h4 class="text-primary">Autosuggest income & spending budget</h4>
|
||||
<p class="text-secondary">
|
||||
This will be based on transaction history. AI can make mistakes, verify before continuing.
|
||||
</p>
|
||||
</div>
|
||||
|
@ -35,7 +35,7 @@
|
|||
budget_form_income_param: { key: "budget_expected_income", value: sprintf("%.2f", @budget.estimated_income) },
|
||||
budget_form_spending_param: { key: "budget_budgeted_spending", value: sprintf("%.2f", @budget.estimated_spending) }
|
||||
} %>
|
||||
<label for="auto_fill" class="maybe-switch"></label>
|
||||
<label for="auto_fill" class="switch"></label>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -25,16 +25,16 @@
|
|||
budget_path(@budget, tab: "budgeted"),
|
||||
class: class_names(
|
||||
base_classes,
|
||||
"bg-white shadow-xs text-gray-900": selected_tab == "budgeted",
|
||||
"text-gray-500": selected_tab != "budgeted"
|
||||
"bg-white shadow-xs text-primary": selected_tab == "budgeted",
|
||||
"text-secondary": selected_tab != "budgeted"
|
||||
) %>
|
||||
|
||||
<%= link_to "Actual",
|
||||
budget_path(@budget, tab: "actuals"),
|
||||
class: class_names(
|
||||
base_classes,
|
||||
"bg-white shadow-xs text-gray-900": selected_tab == "actuals",
|
||||
"text-gray-500": selected_tab != "actuals"
|
||||
"bg-white shadow-xs text-primary": selected_tab == "actuals",
|
||||
"text-secondary": selected_tab != "actuals"
|
||||
) %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<div id="<%= dom_id(category) %>" class="flex justify-between items-center px-4 pb-4 <%= "pt-4" unless category.subcategory? %> <%= "pb-4" unless category.subcategories.any? %> bg-white">
|
||||
<div class="flex w-full items-center gap-2.5">
|
||||
<% if category.subcategory? %>
|
||||
<%= lucide_icon "corner-down-right", class: "shrink-0 w-5 h-5 text-gray-400 ml-2" %>
|
||||
<%= lucide_icon "corner-down-right", class: "shrink-0 w-5 h-5 text-subdued ml-2" %>
|
||||
<% end %>
|
||||
|
||||
<%= render partial: "categories/badge", locals: { category: category } %>
|
||||
</div>
|
||||
<div class="justify-self-end">
|
||||
<%= contextual_menu do %>
|
||||
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<div class="w-48 p-1 text-sm leading-6 text-primary bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<%= contextual_menu_modal_action_item t(".edit"), edit_category_path(category) %>
|
||||
|
||||
<% if category.transactions.any? %>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<%# locals: (title:, categories:) %>
|
||||
|
||||
<div class="rounded-xl bg-gray-25 space-y-1 p-1">
|
||||
<div class="flex items-center gap-1.5 px-4 py-2 text-xs font-medium text-gray-500 uppercase">
|
||||
<div class="flex items-center gap-1.5 px-4 py-2 text-xs font-medium text-secondary uppercase">
|
||||
<p><%= title %></p>
|
||||
<span class="text-gray-400">·</span>
|
||||
<span class="text-subdued">·</span>
|
||||
<p><%= categories.count %></p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
<%= render partial: "categories/badge", locals: { category: transaction.category } %>
|
||||
</button>
|
||||
<div data-menu-target="content" class="absolute z-10 hidden w-screen mt-2 max-w-min cursor-default">
|
||||
<div class="w-80 text-sm font-semibold leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<div class="w-80 text-sm font-semibold leading-6 text-primary bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<%= turbo_frame_tag "category_dropdown", src: category_dropdown_path(category_id: transaction.category_id, transaction_id: transaction.id), loading: :lazy do %>
|
||||
<div class="p-6 flex items-center justify-center">
|
||||
<p class="text-sm text-gray-500 animate-pulse"><%= t(".loading") %></p>
|
||||
<p class="text-sm text-secondary animate-pulse"><%= t(".loading") %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<section class="space-y-4">
|
||||
<header class="flex items-center justify-between">
|
||||
<h1 class="text-gray-900 text-xl font-medium"><%= t(".categories") %></h1>
|
||||
<h1 class="text-primary text-xl font-medium"><%= t(".categories") %></h1>
|
||||
|
||||
<%= link_to new_category_path, class: "btn btn--primary flex items-center gap-1 justify-center", data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon "plus", class: "w-5 h-5" %>
|
||||
|
@ -26,7 +26,7 @@
|
|||
<% else %>
|
||||
<div class="flex justify-center items-center py-20">
|
||||
<div class="text-center flex flex-col items-center max-w-[500px]">
|
||||
<p class="text-sm text-gray-500 mb-4"><%= t(".empty") %></p>
|
||||
<p class="text-sm text-secondary mb-4"><%= t(".empty") %></p>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= button_to t(".bootstrap"), bootstrap_categories_path, class: "btn btn--primary" %>
|
||||
|
||||
|
|
|
@ -13,20 +13,20 @@
|
|||
class: "flex w-full items-center gap-1.5 cursor-pointer" do %>
|
||||
|
||||
<span class="w-5 h-5">
|
||||
<%= lucide_icon("check", class: "w-5 h-5 text-gray-500") if is_selected %>
|
||||
<%= lucide_icon("check", class: "w-5 h-5 text-secondary") if is_selected %>
|
||||
</span>
|
||||
<% if category.subcategory? %>
|
||||
<%= lucide_icon "corner-down-right", class: "shrink-0 w-5 h-5 text-gray-400" %>
|
||||
<%= lucide_icon "corner-down-right", class: "shrink-0 w-5 h-5 text-subdued" %>
|
||||
<% end %>
|
||||
<%= render partial: "categories/badge", locals: { category: category } %>
|
||||
<% end %>
|
||||
|
||||
<%= contextual_menu do %>
|
||||
<div class="w-48 p-1 text-sm leading-6 text-gray-900 bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<div class="w-48 p-1 text-sm leading-6 text-primary bg-white shadow-lg shrink rounded-xl ring-1 ring-gray-900/5">
|
||||
<%= link_to edit_category_path(category),
|
||||
class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg",
|
||||
class: "block w-full py-2 px-3 space-x-2 text-primary hover:bg-gray-50 flex items-center rounded-lg",
|
||||
data: { turbo_frame: :modal } do %>
|
||||
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %>
|
||||
<%= lucide_icon "pencil-line", class: "w-5 h-5 text-secondary" %>
|
||||
|
||||
<span><%= t(".edit") %></span>
|
||||
<% end %>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue