github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/templates/months.html (about)

     1  <!DOCTYPE html>
     2  <html lang="en">
     3  
     4  <head>
     5  	<meta charset="UTF-8">
     6  	<meta name="viewport" content="width=device-width, initial-scale=1.0">
     7  	<title>{{ .YearInterval }} Overview | Budget Manager</title>
     8  
     9  	<!-- Theme Switcher -->
    10  	<script src="{{ asStaticURL `/static/js/theme-switcher.js` }}"></script>
    11  
    12  	<link rel="stylesheet" href="{{ asStaticURL `/static/css/common.css` }}">
    13  
    14  	<style>
    15  		/* | App */
    16  
    17  		#content {
    18  			display: grid;
    19  			grid-template-rows: min-content auto;
    20  			row-gap: 50px;
    21  		}
    22  
    23  		/* || Months */
    24  
    25  		#year {
    26  			display: grid;
    27  			grid-template-columns: min-content auto min-content;
    28  		}
    29  
    30  		.switch-year-btn {
    31  			transform: translateX(-10px);
    32  			width: 45px;
    33  		}
    34  
    35  		#next-year-btn {
    36  			transform: translateX(10px) rotate(180deg);
    37  		}
    38  
    39  		.switch-year-btn .feather-icon {
    40  			height: 100%;
    41  			padding: 0;
    42  		}
    43  
    44  		.switch-year-btn .feather-icon>svg {
    45  			height: 100%;
    46  			width: 100%;
    47  		}
    48  
    49  		#months-list {
    50  			display: grid;
    51  			grid-template-columns: repeat(6, 1fr);
    52  			column-gap: 20px;
    53  			row-gap: 20px;
    54  		}
    55  
    56  		.month {
    57  			padding: 10px 10px 20px;
    58  		}
    59  
    60  		.month.disabled {
    61  			cursor: default;
    62  			opacity: 0.5;
    63  		}
    64  
    65  		.month.disabled .month__results {
    66  			opacity: 0;
    67  		}
    68  
    69  		.month__header {
    70  			font-size: 18px;
    71  		}
    72  
    73  		.month__results {
    74  			display: grid;
    75  			grid-template-columns: min-content max-content;
    76  			column-gap: 10px;
    77  			margin-top: 7px;
    78  		}
    79  
    80  		.month__result {
    81  			text-align: right;
    82  		}
    83  
    84  		/* || Year Overview */
    85  
    86  		#year-overview {
    87  			column-gap: 20px;
    88  			display: grid;
    89  			grid-template-columns: min-content auto;
    90  			height: 100%;
    91  			margin-left: 45px;
    92  			max-height: 400px;
    93  		}
    94  
    95  		#year-overview__results {
    96  			height: min-content;
    97  		}
    98  
    99  		#year-overview__results .card__body {
   100  			column-gap: 10px;
   101  			display: grid;
   102  			grid-template-columns: max-content max-content;
   103  			font-size: 18px;
   104  			height: min-content;
   105  			padding-left: 10px;
   106  			padding-right: 30px;
   107  		}
   108  
   109  		.year-overview__result {
   110  			text-align: right;
   111  		}
   112  
   113  		#year-overview__chart__wrapper {
   114  			position: relative;
   115  			/*
   116  				There's a bug when width and height are 100%. Div isn't decreasing width and height if we resize screen.
   117  				So, use 99% instead.
   118  			*/
   119  			height: 99%;
   120  			width: 99%;
   121  		}
   122  
   123  		/* | Layouts */
   124  
   125  		@media (max-width: 1350px) {
   126  
   127  			.switch-year-btn {
   128  				transform: translateX(-5px);
   129  				width: 35px;
   130  			}
   131  
   132  			#next-year-btn {
   133  				transform: translateX(5px) rotate(180deg);
   134  			}
   135  
   136  			#months-list {
   137  				grid-template-columns: repeat(4, 1fr);
   138  			}
   139  
   140  			.month {
   141  				padding: 10px;
   142  			}
   143  
   144  			#year-overview {
   145  				margin-left: 35px;
   146  			}
   147  
   148  			#year-overview__results .card__title {
   149  				font-size: 18px;
   150  			}
   151  
   152  			#year-overview__results .card__body {
   153  				font-size: 16px;
   154  			}
   155  		}
   156  
   157  		@media (max-width: 1100px) {
   158  
   159  			.month__header {
   160  				font-size: 16px;
   161  			}
   162  
   163  			.month__results {
   164  				font-size: 14px;
   165  			}
   166  		}
   167  	</style>
   168  </head>
   169  
   170  <body>
   171  	<div id="app">
   172  		<div id="header">
   173  			<div>
   174  				<span class="header__path__element">{{ .YearInterval }} Overview</span>
   175  			</div>
   176  		</div>
   177  
   178  		<div id="content">
   179  			<div id="year">
   180  				<div id="prev-year-btn" class="switch-year-btn">
   181  					<a href="/months?offset={{ call $.Add .Offset 1 }}" class="feather-icon">
   182  						{{ template "components/icon" "chevron-left" }}
   183  					</a>
   184  				</div>
   185  
   186  				<div id="months-list">
   187  					{{ range .Months }}
   188  
   189  					{{ $attributes := `class="month card disabled noselect" title="No data for the month"` }}
   190  					{{ if ne .ID 0 }}
   191  					{{ $attributes = (printf `href="/months/month?year=%d&month=%d" class="month card card--hover" title="Go to the month"` .Year .Month)}}
   192  					{{ end }}
   193  
   194  					<a {{ toHTMLAttr $attributes }}>
   195  						<div class="month__header">{{ .Month }} {{ .Year }}</div>
   196  						<div class="month__results">
   197  							<div>Income:</div>
   198  							<div class="month__result money--gain">{{ .TotalIncome }}</div>
   199  							<div>Spend:</div>
   200  							<div class="month__result money--lose">{{ .TotalSpend }}</div>
   201  							<div>Result:</div>
   202  							<div class="month__result">
   203  								{{ if ge .Result 0 }}
   204  								<span class="money--gain">{{ .Result }}</span>
   205  								{{ else }}
   206  								<span class="money--lose">{{ .Result }}</span>
   207  								{{ end }}
   208  							</div>
   209  						</div>
   210  					</a>
   211  					{{ end }}
   212  				</div>
   213  
   214  				<div id="next-year-btn" class="switch-year-btn">
   215  					{{ $offset := call $.Add .Offset -1 }}
   216  					{{ if ge $offset 0 }}
   217  					<a href="/months?offset={{ call $.Add .Offset -1 }}" class="feather-icon">
   218  						{{ template "components/icon" "chevron-left" }}
   219  					</a>
   220  					{{ else }}
   221  					<a class="feather-icon disabled" title="No more months">
   222  						{{ template "components/icon" "chevron-left" }}
   223  					</a>
   224  					{{ end }}
   225  				</div>
   226  			</div>
   227  
   228  			<div id="year-overview">
   229  				<div id="year-overview__results" class="card">
   230  					<div class="card__title noselect">{{ .YearInterval }} Results</div>
   231  
   232  					<div class="card__body">
   233  						<div>Total Income:</div>
   234  						<div class="year-overview__result money--gain">{{ .TotalIncome }}</div>
   235  
   236  						<div>Total Spend:</div>
   237  						<div class="year-overview__result money--lose">{{ .TotalSpend }}</div>
   238  
   239  						<div>Result:</div>
   240  						<div class="year-overview__result">
   241  							{{ if ge .Result 0 }}
   242  							<span class="money--gain">{{ .Result }}</span>
   243  							{{ else }}
   244  							<span class="money--lose">{{ .Result }}</span>
   245  							{{ end }}
   246  						</div>
   247  					</div>
   248  				</div>
   249  
   250  				<div id="year-overview__chart__wrapper">
   251  					<canvas id="year-overview__chart"></canvas>
   252  				</div>
   253  			</div>
   254  		</div>
   255  
   256  		{{ template "components/footer.html" .Footer }}
   257  	</div>
   258  
   259  	<script src="{{ asStaticURL `/static/vendor/chart.js/chart.min.js` }}"></script>
   260  	<script src="{{ asStaticURL `/static/js/chart.js` }}"></script>
   261  
   262  	<script>
   263  		const monthResults = JSON.parse(`{{ .Months }}`);
   264  		const monthNames = ["January", "February", "March", "April", "May", "June",
   265  			"July", "August", "September", "October", "November", "December"];
   266  
   267  		// Create the chart
   268  		const yearOverviewCtx = document.getElementById("year-overview__chart").getContext("2d");
   269  		const yearOverviewChart = new Chart(yearOverviewCtx, {
   270  			type: "line",
   271  			data: {
   272  				labels: monthResults.map(v => monthNames[v["month"] - 1]),
   273  				datasets: [
   274  					// Incomes
   275  					{
   276  						data: monthResults.map(v => v["total_income"]),
   277  						borderColor: "green",
   278  						backgroundColor: "#00ff0018", // green with alpha
   279  						fill: true,
   280  					},
   281  					// Spends
   282  					{
   283  						data: monthResults.map(v => -v["total_spend"]),
   284  						borderColor: "crimson",
   285  						backgroundColor: "#dc143c18", // crimson with alpha
   286  						fill: true,
   287  					}
   288  				],
   289  			},
   290  			options: {
   291  				// Change bezier curves
   292  				elements: {
   293  					line: { tension: 0.2 },
   294  					point: { hitRadius: 5 }
   295  				},
   296  				scales: {
   297  					y: { ticks: { callback: Chart.Ticks.formatters.money } }
   298  				}
   299  			}
   300  		});
   301  
   302  		window.addEventListener(themeChangeEventName, () => {
   303  			const gridLinesColor = getGridLinesColor();
   304  
   305  			// Update color of grid lines
   306  			const scales = yearOverviewChart.options.scales;
   307  			for (const axis of [scales.x, scales.y]) {
   308  				axis.grid.color = gridLinesColor
   309  			}
   310  
   311  			yearOverviewChart.update();
   312  		})
   313  	</script>
   314  </body>
   315  
   316  </html>