1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-19 05:09:38 +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:
Zach Gollwitzer 2025-02-13 11:31:07 -05:00 committed by GitHub
parent c0e290a07e
commit 849c58dd3e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
193 changed files with 1356 additions and 1073 deletions

View 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`.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -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 {
@ -426,4 +68,19 @@
::-webkit-scrollbar-thumb:hover {
background: #a6a6a6;
}
}
.scrollbar {
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: #d6d6d6;
border-radius: 10px;
}
&::-webkit-scrollbar-thumb:hover {
background: #a6a6a6;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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() {

View file

@ -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>

View file

@ -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 %>

View file

@ -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>

View file

@ -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" %>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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" %>

View file

@ -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>

View file

@ -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| %>

View file

@ -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>

View file

@ -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 %>

View file

@ -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 %>

View file

@ -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,

View file

@ -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 %>

View file

@ -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>

View file

@ -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",

View file

@ -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| %>

View file

@ -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>

View file

@ -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>

View file

@ -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 %>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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, "&nbsp;".html_safe, class: "maybe-switch" %>
<%= form.label :is_active, "&nbsp;".html_safe, class: "switch" %>
</div>
<% end %>
<% end %>

View file

@ -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 %>

View file

@ -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>

View file

@ -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") %>

View file

@ -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>

View file

@ -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>

View file

@ -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">

View file

@ -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">&middot;</span>
<span class="text-subdued mx-2">&middot;</span>
<p><%= accounts.count %></p>
<p class="ml-auto"><%= totals_by_currency(collection: accounts, money_method: :balance_money) %></p>
</div>

View file

@ -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">

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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| %>

View file

@ -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 %>

View file

@ -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>

View file

@ -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 %>

View file

@ -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 %>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -9,17 +9,17 @@
<% end %>
<% if budget.available_to_allocate.negative? %>
<p class="text-gray-900 text-sm">&gt; 100% set</p>
<p class="text-primary text-sm">&gt; 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>

View file

@ -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 %>

View file

@ -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",

View file

@ -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 %>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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 %>

View file

@ -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>

View file

@ -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">&middot;</span>
<span class="text-subdued">&middot;</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>

View file

@ -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>

View file

@ -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 %>

View file

@ -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"

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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 %>

View file

@ -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>

View file

@ -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? %>

View file

@ -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">&middot;</span>
<span class="text-subdued">&middot;</span>
<p><%= categories.count %></p>
</div>

View file

@ -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>

View file

@ -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" %>

View file

@ -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