You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

876 lines
19 KiB

  1. @use '../atoms/variables' as *;
  2. @use '../atoms/mixins' as *;
  3. // ─── Page ─────────────────────────────────────────────────────────────────────
  4. .report-page {
  5. @include page-shell;
  6. }
  7. // ─── Header ──────────────────────────────────────────────────────────────────
  8. .report-header {
  9. @include section-header;
  10. padding: $space-4 $space-6;
  11. @include tablet {
  12. flex-direction: column;
  13. align-items: stretch;
  14. gap: $space-3;
  15. }
  16. }
  17. .report-header__title {
  18. font-size: $font-size-xl;
  19. font-weight: $font-weight-bold;
  20. color: var(--header-text);
  21. }
  22. .report-header__right {
  23. display: flex;
  24. align-items: center;
  25. gap: $space-4;
  26. @include tablet {
  27. flex-wrap: wrap;
  28. }
  29. }
  30. // ─── Disabled Tab ────────────────────────────────────────────────────────────
  31. .account-tab--disabled {
  32. opacity: 0.45;
  33. pointer-events: none;
  34. cursor: default;
  35. }
  36. // ─── Content ─────────────────────────────────────────────────────────────────
  37. .report-content {
  38. flex: 1;
  39. max-width: 1200px;
  40. width: 100%;
  41. margin: $space-6 auto;
  42. padding: 0 $space-6;
  43. @include tablet {
  44. padding: 0 $space-4;
  45. }
  46. }
  47. // ─── Karte ───────────────────────────────────────────────────────────────────
  48. .report-card {
  49. @include card;
  50. overflow: hidden;
  51. @include tablet { overflow-x: auto; }
  52. }
  53. // ─── Toolbar ─────────────────────────────────────────────────────────────────
  54. .report-toolbar {
  55. display: flex;
  56. align-items: center;
  57. justify-content: space-between;
  58. padding: $space-3 $space-5;
  59. border-bottom: 1px solid $color-border;
  60. @include tablet {
  61. flex-wrap: wrap;
  62. gap: $space-3;
  63. }
  64. }
  65. .report-toolbar__left {
  66. display: flex;
  67. align-items: center;
  68. gap: $space-6;
  69. }
  70. .report-toolbar__right {
  71. display: flex;
  72. align-items: center;
  73. gap: $space-2;
  74. }
  75. .report-toolbar__export {
  76. @include icon-btn(30px, $radius-sm);
  77. color: $color-text-light;
  78. svg { width: 18px; height: 18px; }
  79. &:hover {
  80. color: var(--color-primary);
  81. background: rgba(var(--color-primary-rgb), 0.08);
  82. }
  83. }
  84. .report-toolbar__separator {
  85. width: 1px;
  86. height: 18px;
  87. background: $color-border;
  88. margin: 0 $space-1;
  89. }
  90. .report-toolbar__action {
  91. display: inline-flex;
  92. align-items: center;
  93. gap: $space-2;
  94. font-size: $font-size-sm;
  95. font-weight: $font-weight-medium;
  96. color: var(--color-primary);
  97. cursor: pointer;
  98. text-decoration: none;
  99. svg {
  100. width: $icon-svg-size;
  101. height: $icon-svg-size;
  102. flex-shrink: 0;
  103. }
  104. &--disabled {
  105. color: $color-text-muted;
  106. pointer-events: none;
  107. cursor: default;
  108. }
  109. }
  110. // ─── Tabelle ─────────────────────────────────────────────────────────────────
  111. .report-table {
  112. width: 100%;
  113. @include tablet { min-width: 900px; }
  114. }
  115. .report-table__head,
  116. .report-table__row {
  117. display: grid;
  118. grid-template-columns:
  119. 110px // Datum
  120. 140px // Kunde
  121. 130px // Projekt
  122. 120px // Leistung
  123. 140px // Benutzer
  124. 120px // Label
  125. 1fr // Bemerkung
  126. 80px // Stunden
  127. 100px // Umsatz
  128. 88px; // Aktionen
  129. align-items: center;
  130. border-bottom: 1px solid $color-border;
  131. padding: 0 $space-5;
  132. }
  133. .report-table__head {
  134. padding-top: $space-2;
  135. padding-bottom: $space-2;
  136. .report-table__cell {
  137. font-size: $font-size-xs;
  138. font-weight: $font-weight-bold;
  139. color: $color-text-base;
  140. text-transform: uppercase;
  141. letter-spacing: 0.03em;
  142. line-height: 1.3;
  143. }
  144. }
  145. .report-table__row {
  146. padding-top: $space-3;
  147. padding-bottom: $space-3;
  148. transition: background $transition-fast;
  149. &:hover {
  150. background: rgba(var(--color-primary-rgb), 0.05);
  151. .report-action-btn { opacity: 1; }
  152. }
  153. &--invoiced .report-table__cell {
  154. &--date, &--client, &--project, &--service, &--label,
  155. &--user, &--note, &--duration, &--revenue {
  156. color: $color-text-light;
  157. }
  158. }
  159. &--editing {
  160. background: rgba(var(--color-primary-rgb), 0.05);
  161. .report-table__cell--actions { visibility: hidden; }
  162. }
  163. &:last-child { border-bottom: none; }
  164. }
  165. .report-table__cell {
  166. font-size: $font-size-base;
  167. color: $color-text-base;
  168. padding-right: $space-3;
  169. line-height: 1.4;
  170. min-width: 0;
  171. &--duration,
  172. &--revenue {
  173. text-align: right;
  174. padding-right: $space-4;
  175. white-space: nowrap;
  176. font-variant-numeric: tabular-nums;
  177. }
  178. &--actions {
  179. display: flex;
  180. align-items: center;
  181. justify-content: flex-end;
  182. gap: $space-1;
  183. padding-right: 0;
  184. }
  185. &--note {
  186. color: $color-text-muted;
  187. font-size: $font-size-sm;
  188. @include text-truncate;
  189. }
  190. }
  191. .report-table__cell--sortable {
  192. cursor: pointer;
  193. user-select: none;
  194. &:hover .report-table__cell-label { color: var(--color-primary); }
  195. }
  196. .report-table__cell--sorted .report-table__cell-label {
  197. color: var(--color-primary);
  198. }
  199. .report-table__cell-label {
  200. transition: color $transition-fast;
  201. }
  202. .report-table__sort-icon {
  203. margin-left: 2px;
  204. font-size: $font-size-xs;
  205. }
  206. .report-table__summary {
  207. display: block;
  208. font-size: $font-size-xs;
  209. font-weight: $font-weight-regular;
  210. color: $color-text-muted;
  211. margin-top: 1px;
  212. }
  213. .report-table__label {
  214. display: inline-block;
  215. font-size: $font-size-xs;
  216. color: var(--color-primary);
  217. background: rgba(var(--color-primary-rgb), 0.08);
  218. padding: 1px $space-2;
  219. border-radius: $radius-sm;
  220. margin-right: $space-1;
  221. }
  222. .report-table__empty {
  223. padding: $space-10 $space-5;
  224. text-align: center;
  225. color: $color-text-muted;
  226. font-size: $font-size-sm;
  227. }
  228. // ─── Aktions-Buttons (Edit / Delete) ─────────────────────────────────────────
  229. .report-action-btn {
  230. @include icon-btn(26px, $radius-sm);
  231. opacity: 0;
  232. color: $color-text-light;
  233. svg { width: $icon-svg-size; height: $icon-svg-size; }
  234. @include tablet { opacity: 1; }
  235. &:hover {
  236. color: $color-text-muted;
  237. background: rgba($color-text-dark, 0.06);
  238. }
  239. &--delete:hover {
  240. color: $color-error;
  241. background: rgba($color-error, 0.08);
  242. }
  243. }
  244. // ─── Schloss-Button ──────────────────────────────────────────────────────────
  245. .report-lock {
  246. @include icon-btn(24px, $radius-sm);
  247. color: $color-text-light;
  248. svg { width: $icon-svg-size; height: $icon-svg-size; }
  249. &:hover {
  250. color: $color-text-muted;
  251. background: rgba($color-text-dark, 0.06);
  252. }
  253. &--invoiced {
  254. color: $color-text-dark;
  255. &:hover {
  256. color: $color-text-dark;
  257. background: rgba($color-text-dark, 0.06);
  258. }
  259. }
  260. }
  261. // ─── Inline-Edit-Formular ────────────────────────────────────────────────────
  262. .report-row__edit {
  263. grid-column: 1 / -1;
  264. padding: $space-4 0;
  265. background: rgba(var(--color-primary-rgb), 0.04);
  266. border-top: 1px solid $color-border;
  267. }
  268. .report-row__edit-grid {
  269. display: grid;
  270. grid-template-columns: 140px 1fr;
  271. gap: $space-3 $space-5;
  272. align-items: center;
  273. max-width: 680px;
  274. @include tablet {
  275. grid-template-columns: 1fr;
  276. gap: $space-3;
  277. }
  278. }
  279. .report-row__edit-label {
  280. @include form-label;
  281. @include tablet {
  282. text-align: left;
  283. padding-right: 0;
  284. }
  285. }
  286. .report-row__edit-field {
  287. display: flex;
  288. align-items: center;
  289. gap: $space-2;
  290. &--selects {
  291. gap: $space-3;
  292. .select {
  293. flex: 1;
  294. min-width: 160px;
  295. }
  296. @include tablet {
  297. flex-direction: column;
  298. .select {
  299. min-width: 0;
  300. width: 100%;
  301. }
  302. }
  303. }
  304. .textarea {
  305. width: 100%;
  306. }
  307. }
  308. .report-row__edit-actions {
  309. grid-column: 2;
  310. display: flex;
  311. gap: $space-3;
  312. padding-top: $space-2;
  313. @include tablet {
  314. grid-column: 1;
  315. .btn { flex: 1; }
  316. }
  317. }
  318. // ─── Pagination-Footer ────────────────────────────────────────────────────────
  319. .report-pagination {
  320. display: grid;
  321. grid-template-columns: 1fr 80px 100px 88px;
  322. align-items: center;
  323. padding: $space-3 $space-5;
  324. border-top: 1px solid $color-border;
  325. font-size: $font-size-sm;
  326. color: $color-text-muted;
  327. }
  328. .report-pagination__limits {
  329. display: flex;
  330. align-items: center;
  331. gap: $space-2;
  332. a {
  333. color: var(--color-primary);
  334. text-decoration: underline;
  335. cursor: pointer;
  336. &:hover { color: var(--color-primary-dark); }
  337. }
  338. strong {
  339. color: $color-text-dark;
  340. font-weight: $font-weight-bold;
  341. }
  342. }
  343. .report-pagination__duration,
  344. .report-pagination__revenue {
  345. text-align: right;
  346. padding-right: $space-4;
  347. font-weight: $font-weight-medium;
  348. color: $color-text-muted;
  349. font-variant-numeric: tabular-nums;
  350. white-space: nowrap;
  351. }
  352. .report-pagination__lock-spacer {
  353. // Platzhalter – hält Spalten-Ausrichtung mit der Tabelle
  354. }
  355. // ─── Toolbar-Button (klickbar) ────────────────────────────────────────────────
  356. button.report-toolbar__action {
  357. background: none;
  358. border: none;
  359. cursor: pointer;
  360. font-family: $font-family-base;
  361. padding: $space-1 $space-3;
  362. margin: (-$space-1) (-$space-3);
  363. border-radius: $radius-pill;
  364. transition: background $transition-fast, color $transition-fast;
  365. &--active {
  366. background: $color-text-dark;
  367. color: $color-white;
  368. svg path,
  369. svg circle {
  370. stroke: $color-white;
  371. }
  372. }
  373. }
  374. // ─── Filter-Panel ─────────────────────────────────────────────────────────────
  375. .report-filter {
  376. background: $color-card;
  377. border-bottom: 1px solid $color-border;
  378. padding: $space-5 $space-5 0;
  379. }
  380. .report-filter__body {
  381. display: flex;
  382. gap: $space-10;
  383. @include tablet {
  384. flex-direction: column;
  385. gap: $space-6;
  386. }
  387. }
  388. .report-filter__col {
  389. flex: 1;
  390. min-width: 0;
  391. max-width: 66%;
  392. @include tablet { max-width: 100%; }
  393. }
  394. .report-filter__heading {
  395. font-size: $font-size-xs;
  396. font-weight: $font-weight-bold;
  397. color: $color-text-muted;
  398. text-transform: uppercase;
  399. letter-spacing: 0.06em;
  400. margin-bottom: $space-3;
  401. }
  402. // ─── Filter-Row ───────────────────────────────────────────────────────────────
  403. .filter-row {
  404. display: grid;
  405. grid-template-columns: 160px 1fr;
  406. align-items: flex-start;
  407. gap: $space-3;
  408. padding: $space-2 0;
  409. border-bottom: 1px solid rgba($color-border, 0.6);
  410. &:last-child { border-bottom: none; }
  411. @include mobile {
  412. grid-template-columns: 1fr;
  413. }
  414. &--inactive {
  415. .filter-select,
  416. .filter-note-input,
  417. .filter-period-select,
  418. .filter-radio {
  419. opacity: 0.5;
  420. }
  421. .filter-select,
  422. .filter-note-input,
  423. .filter-period-select {
  424. color: $color-text-muted;
  425. }
  426. .filter-row__add,
  427. .filter-neg {
  428. opacity: 0.4;
  429. }
  430. .filter-neg {
  431. pointer-events: none;
  432. }
  433. }
  434. }
  435. .filter-row__label {
  436. display: flex;
  437. align-items: center;
  438. gap: $space-2;
  439. cursor: pointer;
  440. font-size: $font-size-sm;
  441. color: $color-text-base;
  442. padding-top: 7px;
  443. user-select: none;
  444. }
  445. .filter-row__checkbox {
  446. width: 14px;
  447. height: 14px;
  448. cursor: pointer;
  449. flex-shrink: 0;
  450. accent-color: var(--color-primary);
  451. }
  452. // ─── Body: Controls + Meta nebeneinander ────────────────────────────────────
  453. .filter-row__body {
  454. display: flex;
  455. align-items: flex-start;
  456. gap: $space-3;
  457. }
  458. .filter-row__controls {
  459. display: flex;
  460. flex-direction: column;
  461. gap: $space-2;
  462. min-width: 0;
  463. flex: 1;
  464. }
  465. .filter-row__control-group {
  466. display: flex;
  467. align-items: center;
  468. gap: $space-2;
  469. .filter-select,
  470. .filter-note-input,
  471. .label-input-wrap {
  472. width: 300px;
  473. max-width: 100%;
  474. @include tablet { width: 100%; }
  475. }
  476. &--period {
  477. flex-direction: column;
  478. align-items: flex-start;
  479. gap: $space-2;
  480. }
  481. &--radio {
  482. padding-top: 7px;
  483. gap: $space-4;
  484. }
  485. }
  486. // ─── Meta: Plus-Button + Negativfilter ──────────────────────────────────────
  487. .filter-row__meta {
  488. display: flex;
  489. align-items: center;
  490. gap: $space-3;
  491. padding-top: 7px;
  492. flex-shrink: 0;
  493. white-space: nowrap;
  494. &--no-add {
  495. padding-left: calc(22px + #{$space-3});
  496. }
  497. }
  498. // ─── Plus- und Minus-Button ───────────────────────────────────────────────────
  499. .filter-row__add {
  500. @include icon-btn(22px, $radius-sm);
  501. border: 1px solid $color-input-border;
  502. background: $color-white;
  503. font-size: $font-size-md;
  504. line-height: 1;
  505. color: $color-text-muted;
  506. &:hover {
  507. border-color: var(--color-primary);
  508. color: var(--color-primary);
  509. }
  510. }
  511. .filter-row__remove {
  512. @include icon-btn(20px, $radius-sm);
  513. font-size: $font-size-md;
  514. line-height: 1;
  515. color: $color-text-light;
  516. &:hover {
  517. color: $color-error;
  518. background: rgba($color-error, 0.08);
  519. }
  520. }
  521. // ─── Zeitraum: Custom-Datumsfelder ───────────────────────────────────────────
  522. .filter-custom-dates {
  523. display: flex;
  524. flex-direction: column;
  525. gap: $space-2;
  526. margin-top: $space-2;
  527. }
  528. .filter-date-group {
  529. display: flex;
  530. align-items: center;
  531. gap: $space-2;
  532. }
  533. .filter-date-label {
  534. font-size: $font-size-sm;
  535. color: $color-text-muted;
  536. width: 26px;
  537. flex-shrink: 0;
  538. }
  539. .filter-date-select {
  540. width: auto;
  541. display: inline-block;
  542. &--sm {
  543. padding-right: $space-6;
  544. min-width: 60px;
  545. }
  546. &--month {
  547. padding-right: $space-6;
  548. min-width: 100px;
  549. }
  550. }
  551. // ─── Radio-Filter (Abgeschlossen?) ────────────────────────────────────────────
  552. .filter-radio {
  553. display: inline-flex;
  554. align-items: center;
  555. gap: $space-1;
  556. font-size: $font-size-sm;
  557. color: $color-text-base;
  558. cursor: pointer;
  559. user-select: none;
  560. accent-color: var(--color-primary);
  561. }
  562. // ─── Filter-Footer ────────────────────────────────────────────────────────────
  563. .report-filter__footer {
  564. display: flex;
  565. align-items: center;
  566. gap: $space-4;
  567. padding: $space-4 0;
  568. }
  569. .filter-footer__link {
  570. background: none;
  571. border: none;
  572. padding: 0;
  573. cursor: pointer;
  574. font-family: $font-family-base;
  575. font-size: $font-size-sm;
  576. color: $color-text-muted;
  577. text-decoration: underline;
  578. text-underline-offset: 2px;
  579. transition: color $transition-fast;
  580. &:hover { color: $color-text-base; }
  581. }
  582. // ─── Negativfilter-Checkbox ───────────────────────────────────────────────────
  583. .filter-neg {
  584. display: inline-flex;
  585. align-items: center;
  586. gap: $space-1;
  587. font-size: $font-size-sm;
  588. color: $color-text-muted;
  589. cursor: pointer;
  590. user-select: none;
  591. white-space: nowrap;
  592. input[type="checkbox"] {
  593. width: 13px;
  594. height: 13px;
  595. cursor: pointer;
  596. accent-color: $color-warning;
  597. flex-shrink: 0;
  598. }
  599. &:has(input:checked) {
  600. color: $color-warning;
  601. font-weight: $font-weight-medium;
  602. }
  603. }
  604. // ─── Invoice Modal ───────────────────────────────────────────────────────────
  605. .invoice-modal {
  606. max-width: 620px;
  607. max-height: 90vh;
  608. display: flex;
  609. flex-direction: column;
  610. }
  611. .invoice-modal .modal-card__body {
  612. overflow-y: auto;
  613. min-height: 0;
  614. }
  615. .invoice-modal__group {
  616. display: flex;
  617. flex-direction: column;
  618. gap: $space-2;
  619. }
  620. .invoice-modal__group-label {
  621. font-size: $font-size-sm;
  622. font-weight: $font-weight-medium;
  623. color: $color-text-dark;
  624. }
  625. .invoice-modal__radios {
  626. display: flex;
  627. gap: $space-5;
  628. flex-wrap: wrap;
  629. }
  630. .invoice-modal__radio {
  631. display: inline-flex;
  632. align-items: center;
  633. gap: $space-2;
  634. font-size: $font-size-sm;
  635. color: $color-text-base;
  636. cursor: pointer;
  637. user-select: none;
  638. input[type='radio'] {
  639. accent-color: var(--color-primary);
  640. width: 15px;
  641. height: 15px;
  642. cursor: pointer;
  643. }
  644. }
  645. .invoice-modal__invoiced-check {
  646. display: inline-flex;
  647. align-items: center;
  648. gap: $space-2;
  649. font-size: $font-size-sm;
  650. color: $color-text-base;
  651. cursor: pointer;
  652. user-select: none;
  653. margin-right: auto;
  654. input[type='checkbox'] {
  655. accent-color: var(--color-primary);
  656. width: 15px;
  657. height: 15px;
  658. cursor: pointer;
  659. }
  660. }
  661. .invoice-modal__preview {
  662. min-height: 80px;
  663. }
  664. .invoice-modal__loading,
  665. .invoice-modal__empty {
  666. padding: $space-6;
  667. text-align: center;
  668. color: $color-text-muted;
  669. font-size: $font-size-sm;
  670. }
  671. // ─── Invoice Preview Table ───────────────────────────────────────────────────
  672. .invoice-preview__table {
  673. border: 1px solid $color-border;
  674. border-radius: $radius-md;
  675. overflow: hidden;
  676. }
  677. .invoice-preview__head,
  678. .invoice-preview__row,
  679. .invoice-preview__foot {
  680. display: grid;
  681. grid-template-columns: 1fr 80px 70px 100px 100px;
  682. align-items: center;
  683. padding: $space-2 $space-4;
  684. gap: $space-2;
  685. }
  686. .invoice-preview__head {
  687. background: rgba($color-border, 0.3);
  688. border-bottom: 1px solid $color-border;
  689. .invoice-preview__cell {
  690. font-size: $font-size-xs;
  691. font-weight: $font-weight-bold;
  692. color: $color-text-muted;
  693. text-transform: uppercase;
  694. letter-spacing: 0.03em;
  695. }
  696. }
  697. .invoice-preview__row {
  698. border-bottom: 1px solid rgba($color-border, 0.6);
  699. &:last-child { border-bottom: none; }
  700. }
  701. .invoice-preview__foot {
  702. border-top: 1px solid $color-border;
  703. background: rgba($color-border, 0.15);
  704. }
  705. .invoice-preview__cell {
  706. font-size: $font-size-sm;
  707. color: $color-text-base;
  708. &--name {
  709. @include text-truncate;
  710. }
  711. &--num {
  712. text-align: right;
  713. font-variant-numeric: tabular-nums;
  714. white-space: nowrap;
  715. }
  716. &--unit {
  717. color: $color-text-muted;
  718. }
  719. &--total {
  720. font-weight: $font-weight-bold;
  721. color: $color-text-dark;
  722. }
  723. }
  724. .invoice-preview__desc {
  725. margin-top: $space-1;
  726. font-size: $font-size-xs;
  727. color: $color-text-muted;
  728. white-space: pre-line;
  729. line-height: 1.5;
  730. }