Merge pull request '🚧 Commence l'ajout de calendrier' (#8) from ui/2/calendar into main

Reviewed-on: #8
This commit is contained in:
Shikiryu 2022-03-30 17:40:33 +02:00
commit a1853e2850
12 changed files with 1098 additions and 25 deletions

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use DateInterval;
use DateTime; use DateTime;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
@ -47,6 +48,7 @@ class PageController extends Controller
$user = Auth::user(); $user = Auth::user();
return view('pages.index', [ return view('pages.index', [
'start_date'=> min((new DateTime())->sub(new DateInterval('P1Y')), $user->created_at),
'checkword' => $user->checkword, 'checkword' => $user->checkword,
'pages' => $pages, 'pages' => $pages,
]); ]);

67
public/css/app.css vendored
View File

@ -12385,6 +12385,73 @@ select {
.ease-in { .ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1); transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
} }
/*
* react-calendar-heatmap styles
*
* All of the styles in this file are optional and configurable!
* The github and gitlab color scales are provided for reference.
*/
@media all and (max-width: 768px) {
svg.react-calendar-heatmap {
transform: rotate(90deg);
}
}
.react-calendar-heatmap text {
font-size: 10px;
fill: #aaa;
}
.react-calendar-heatmap .react-calendar-heatmap-small-text {
font-size: 5px;
}
.react-calendar-heatmap rect:hover {
stroke: #555;
stroke-width: 1px;
}
/*
* Default color scale
*/
.react-calendar-heatmap .color-empty {
fill: #eeeeee;
}
.react-calendar-heatmap .color-filled {
fill: #8cc665;
}
/*
* Github color scale
*/
.react-calendar-heatmap .color-github-0 {
fill: #eeeeee;
}
.react-calendar-heatmap .color-github-1 {
fill: #d6e685;
}
.react-calendar-heatmap .color-github-2 {
fill: #8cc665;
}
.react-calendar-heatmap .color-github-3 {
fill: #44a340;
}
.react-calendar-heatmap .color-github-4 {
fill: #1e6823;
}
/*
* Gitlab color scale
*/
.react-calendar-heatmap .color-gitlab-0 {
fill: #ededed;
}
.react-calendar-heatmap .color-gitlab-1 {
fill: #acd5f2;
}
.react-calendar-heatmap .color-gitlab-2 {
fill: #7fa8d1;
}
.react-calendar-heatmap .color-gitlab-3 {
fill: #49729b;
}
.react-calendar-heatmap .color-gitlab-4 {
fill: #254e77;
}
.hover\:border-gray-300:hover { .hover\:border-gray-300:hover {
--tw-border-opacity: 1; --tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity)); border-color: rgb(209 213 219 / var(--tw-border-opacity));

524
public/js/app.js vendored
View File

@ -36044,6 +36044,387 @@ __webpack_require__(/*! ./components/user/First */ "./resources/js/components/us
/***/ }), /***/ }),
/***/ "./resources/js/components/calendar/CalendarHeatmap.tsx":
/*!**************************************************************!*\
!*** ./resources/js/components/calendar/CalendarHeatmap.tsx ***!
\**************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants.js */ "./resources/js/components/calendar/constants.js");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../utils */ "./resources/js/utils.ts");
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
var SQUARE_SIZE = 10;
var MONTH_LABEL_GUTTER_SIZE = 4;
var CSS_PSEUDO_NAMESPACE = 'react-calendar-heatmap-';
function CalendarHeatmap(_ref) {
var values = _ref.values,
startDate = _ref.startDate,
endDate = _ref.endDate,
gutterSize = _ref.gutterSize,
horizontal = _ref.horizontal,
showMonthLabels = _ref.showMonthLabels,
showWeekdayLabels = _ref.showWeekdayLabels,
showOutOfRangeDays = _ref.showOutOfRangeDays,
tooltipDataAttrs = _ref.tooltipDataAttrs,
onClick = _ref.onClick,
onMouseOver = _ref.onMouseOver,
onMouseLeave = _ref.onMouseLeave,
transformDayElement = _ref.transformDayElement;
var cachedValues = {};
for (var i in values) {
var value = values[i];
var date = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.convertToDate)(value.date);
var index = Math.floor((date.getTime() - getStartDateWithEmptyDays().getTime()) / _constants_js__WEBPACK_IMPORTED_MODULE_1__.MILLISECONDS_IN_ONE_DAY);
cachedValues[index] = {
date: value.date,
event: value.event,
className: classForValue(value.id),
title: titleForValue(value.id),
tooltipDataAttrs: getTooltipDataAttrsForValue(value.id)
};
}
function getDateDifferenceInDays() {
var timeDiff = getEndDate().getTime() - (0,_utils__WEBPACK_IMPORTED_MODULE_2__.convertToDate)(startDate).getTime();
return Math.ceil(timeDiff / _constants_js__WEBPACK_IMPORTED_MODULE_1__.MILLISECONDS_IN_ONE_DAY);
}
function classForValue(value) {
return value ? 'color-filled' : 'color-empty';
}
function titleForValue(value) {
return value;
}
function getSquareSizeWithGutter() {
return SQUARE_SIZE + gutterSize;
}
function getMonthLabelSize() {
if (!showMonthLabels) {
return 0;
}
if (horizontal) {
return SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE;
}
return 2 * (SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE);
}
function getWeekdayLabelSize() {
if (!showWeekdayLabels) {
return 0;
}
if (horizontal) {
return 30;
}
return SQUARE_SIZE * 1.5;
}
function getStartDate() {
return (0,_utils__WEBPACK_IMPORTED_MODULE_2__.shiftDate)(getEndDate(), -getDateDifferenceInDays() + 1); // +1 because endDate is inclusive
}
function getEndDate() {
return (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getBeginningTimeForDate)((0,_utils__WEBPACK_IMPORTED_MODULE_2__.convertToDate)(endDate));
}
function getStartDateWithEmptyDays() {
return (0,_utils__WEBPACK_IMPORTED_MODULE_2__.shiftDate)(getStartDate(), -getNumEmptyDaysAtStart());
}
function getNumEmptyDaysAtStart() {
return getStartDate().getDay();
}
function getNumEmptyDaysAtEnd() {
return _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK - 1 - getEndDate().getDay();
}
function getWeekCount() {
var numDaysRoundedToWeek = getDateDifferenceInDays() + getNumEmptyDaysAtStart() + getNumEmptyDaysAtEnd();
return Math.ceil(numDaysRoundedToWeek / _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK);
}
function getWeekWidth() {
return _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK * getSquareSizeWithGutter();
}
function getWidth() {
return getWeekCount() * getSquareSizeWithGutter() - (gutterSize - getWeekdayLabelSize());
}
function getHeight() {
return getWeekWidth() + (getMonthLabelSize() - gutterSize) + getWeekdayLabelSize();
}
function getValueForIndex(index) {
if (cachedValues[index]) {
console.log(index, cachedValues);
return cachedValues[index].event;
}
return null;
}
function getClassNameForIndex(index) {
if (cachedValues[index]) {
return cachedValues[index].className;
}
return classForValue(null);
}
function getTitleForIndex(index) {
if (cachedValues[index]) {
return cachedValues[index].title;
}
return titleForValue ? titleForValue(null) : null;
}
function getTooltipDataAttrsForIndex(index) {
if (cachedValues[index]) {
return cachedValues[index].tooltipDataAttrs;
}
return getTooltipDataAttrsForValue({
date: null,
count: null
});
}
function getTooltipDataAttrsForValue(value) {
if (typeof tooltipDataAttrs === 'function') {
return tooltipDataAttrs(value);
}
return tooltipDataAttrs;
}
function getTransformForWeek(weekIndex) {
if (horizontal) {
return "translate(".concat(weekIndex * getSquareSizeWithGutter(), ", 0)");
}
return "translate(0, ".concat(weekIndex * getSquareSizeWithGutter(), ")");
}
function getTransformForWeekdayLabels() {
if (horizontal) {
return "translate(".concat(SQUARE_SIZE, ", ").concat(getMonthLabelSize(), ")");
}
return "";
}
function getTransformForMonthLabels() {
if (horizontal) {
return "translate(".concat(getWeekdayLabelSize(), ", 0)");
}
return "translate(".concat(getWeekWidth() + MONTH_LABEL_GUTTER_SIZE, ", ").concat(getWeekdayLabelSize(), ")");
}
function getTransformForAllWeeks() {
if (horizontal) {
return "translate(".concat(getWeekdayLabelSize(), ", ").concat(getMonthLabelSize(), ")");
}
return "translate(0, ".concat(getWeekdayLabelSize(), ")");
}
function getViewBox() {
if (horizontal) {
return "0 0 ".concat(getWidth(), " ").concat(getHeight());
}
return "0 0 ".concat(getHeight(), " ").concat(getWidth());
}
function getSquareCoordinates(dayIndex) {
if (horizontal) {
return [0, dayIndex * getSquareSizeWithGutter()];
}
return [dayIndex * getSquareSizeWithGutter(), 0];
}
function getWeekdayLabelCoordinates(dayIndex) {
if (horizontal) {
return [0, (dayIndex + 1) * SQUARE_SIZE + dayIndex * gutterSize];
}
return [dayIndex * SQUARE_SIZE + dayIndex * gutterSize, SQUARE_SIZE];
}
function getMonthLabelCoordinates(weekIndex) {
if (horizontal) {
return [weekIndex * getSquareSizeWithGutter(), getMonthLabelSize() - MONTH_LABEL_GUTTER_SIZE];
}
var verticalOffset = -2;
return [0, (weekIndex + 1) * getSquareSizeWithGutter() + verticalOffset];
}
function handleClick(value) {
if (onClick) {
onClick(value);
}
}
function handleMouseOver(e, value) {
if (onMouseOver) {
onMouseOver(e, value);
}
}
function handleMouseLeave(e, value) {
if (onMouseLeave) {
onMouseLeave(e, value);
}
}
function renderSquare(dayIndex, index) {
var indexOutOfRange = index < getNumEmptyDaysAtStart() || index >= getNumEmptyDaysAtStart() + getDateDifferenceInDays();
if (indexOutOfRange && !showOutOfRangeDays) {
return null;
}
var _getSquareCoordinates = getSquareCoordinates(dayIndex),
_getSquareCoordinates2 = _slicedToArray(_getSquareCoordinates, 2),
x = _getSquareCoordinates2[0],
y = _getSquareCoordinates2[1];
var value = getValueForIndex(index);
var rect = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("rect", Object.assign({
key: index,
width: SQUARE_SIZE,
height: SQUARE_SIZE,
x: x,
y: y,
className: getClassNameForIndex(index),
onClick: function onClick() {
return handleClick(value);
},
onMouseOver: function onMouseOver(e) {
return handleMouseOver(e, value);
},
onMouseLeave: function onMouseLeave(e) {
return handleMouseLeave(e, value);
}
}, getTooltipDataAttrsForIndex(index)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("title", null, getTitleForIndex(index)));
return transformDayElement ? transformDayElement(rect, value, index) : rect;
}
function renderWeek(weekIndex) {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("g", {
key: weekIndex,
transform: getTransformForWeek(weekIndex),
className: "".concat(CSS_PSEUDO_NAMESPACE, "week")
}, (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getRange)(_constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK).map(function (dayIndex) {
return renderSquare(dayIndex, weekIndex * _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK + dayIndex);
}));
}
function renderAllWeeks() {
return (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getRange)(getWeekCount()).map(function (weekIndex) {
return renderWeek(weekIndex);
});
}
function renderMonthLabels() {
if (!showMonthLabels) {
return null;
}
var weekRange = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getRange)(getWeekCount() - 1); // don't render for last week, because label will be cut off
return weekRange.map(function (weekIndex) {
var endOfWeek = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.shiftDate)(getStartDateWithEmptyDays(), (weekIndex + 1) * _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK);
var _getMonthLabelCoordin = getMonthLabelCoordinates(weekIndex),
_getMonthLabelCoordin2 = _slicedToArray(_getMonthLabelCoordin, 2),
x = _getMonthLabelCoordin2[0],
y = _getMonthLabelCoordin2[1];
return endOfWeek.getDate() >= 1 && endOfWeek.getDate() <= _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAYS_IN_WEEK ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("text", {
key: weekIndex,
x: x,
y: y,
className: "".concat(CSS_PSEUDO_NAMESPACE, "month-label")
}, _constants_js__WEBPACK_IMPORTED_MODULE_1__.MONTH_LABELS[endOfWeek.getMonth()]) : null;
});
}
function renderWeekdayLabels() {
if (!showWeekdayLabels) {
return null;
}
return _constants_js__WEBPACK_IMPORTED_MODULE_1__.DAY_LABELS.map(function (weekdayLabel, dayIndex) {
var _getWeekdayLabelCoord = getWeekdayLabelCoordinates(dayIndex),
_getWeekdayLabelCoord2 = _slicedToArray(_getWeekdayLabelCoord, 2),
x = _getWeekdayLabelCoord2[0],
y = _getWeekdayLabelCoord2[1];
var cssClasses = "".concat(horizontal ? '' : "".concat(CSS_PSEUDO_NAMESPACE, "small-text"), " ").concat(CSS_PSEUDO_NAMESPACE, "weekday-label"); // eslint-disable-next-line no-bitwise
return dayIndex & 1 ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("text", {
key: "".concat(x).concat(y),
x: x,
y: y,
className: cssClasses
}, weekdayLabel) : null;
});
}
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("svg", {
className: "react-calendar-heatmap",
viewBox: getViewBox()
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("g", {
transform: getTransformForMonthLabels(),
className: "".concat(CSS_PSEUDO_NAMESPACE, "month-labels")
}, renderMonthLabels()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("g", {
transform: getTransformForAllWeeks(),
className: "".concat(CSS_PSEUDO_NAMESPACE, "all-weeks")
}, renderAllWeeks()), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createElement("g", {
transform: getTransformForWeekdayLabels(),
className: "".concat(CSS_PSEUDO_NAMESPACE, "weekday-labels")
}, renderWeekdayLabels()));
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (CalendarHeatmap);
/***/ }),
/***/ "./resources/js/components/pages/App.tsx": /***/ "./resources/js/components/pages/App.tsx":
/*!***********************************************!*\ /*!***********************************************!*\
!*** ./resources/js/components/pages/App.tsx ***! !*** ./resources/js/components/pages/App.tsx ***!
@ -36059,15 +36440,16 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _List__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./List */ "./resources/js/components/pages/List.tsx"); /* harmony import */ var _List__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./List */ "./resources/js/components/pages/List.tsx");
/* harmony import */ var _Prompt__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Prompt */ "./resources/js/components/pages/Prompt.tsx"); /* harmony import */ var _Prompt__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Prompt */ "./resources/js/components/pages/Prompt.tsx");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react */ "./node_modules/react/index.js"); /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Alert/Alert.js"); /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Alert/Alert.js");
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/AlertTitle/AlertTitle.js"); /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/AlertTitle/AlertTitle.js");
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Button/Button.js"); /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Button/Button.js");
/* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Divider/Divider.js"); /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Divider/Divider.js");
/* harmony import */ var storage_encryption__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! storage-encryption */ "./node_modules/storage-encryption/build/index.js"); /* harmony import */ var storage_encryption__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! storage-encryption */ "./node_modules/storage-encryption/build/index.js");
/* harmony import */ var storage_encryption__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(storage_encryption__WEBPACK_IMPORTED_MODULE_4__); /* harmony import */ var storage_encryption__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(storage_encryption__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router/esm/react-router.js"); /* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router/esm/react-router.js");
/* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router-dom/esm/react-router-dom.js"); /* harmony import */ var react_router_dom__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router-dom/esm/react-router-dom.js");
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../utils */ "./resources/js/utils.ts"); /* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../utils */ "./resources/js/utils.ts");
/* harmony import */ var _calendar_CalendarHeatmap__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../calendar/CalendarHeatmap */ "./resources/js/components/calendar/CalendarHeatmap.tsx");
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@ -36101,6 +36483,7 @@ var __rest = undefined && undefined.__rest || function (s, e) {
var app = document.getElementById('app'); var app = document.getElementById('app');
var word = "shikiryu"; // FIXME should be in db and ≠ between users var word = "shikiryu"; // FIXME should be in db and ≠ between users
@ -36110,12 +36493,14 @@ var getPageContentUrl,
postUrl, postUrl,
removeUrl, removeUrl,
checkword, checkword,
startDate,
csrf = ""; csrf = "";
if (app) { if (app) {
getPageContentUrl = "" + app.getAttribute('data-url'); getPageContentUrl = "" + app.getAttribute('data-url');
pages = JSON.parse("" + app.getAttribute('data-list')); pages = JSON.parse("" + app.getAttribute('data-list'));
postUrl = "" + app.getAttribute('data-post'); postUrl = "" + app.getAttribute('data-post');
startDate = "" + app.getAttribute('data-start');
removeUrl = "" + app.getAttribute('data-remove'); removeUrl = "" + app.getAttribute('data-remove');
csrf = "" + app.getAttribute('data-csrf'); csrf = "" + app.getAttribute('data-csrf');
checkword = "" + app.getAttribute('data-checkword'); checkword = "" + app.getAttribute('data-checkword');
@ -36132,7 +36517,7 @@ function App() {
passphrase = _React$useState4[0], passphrase = _React$useState4[0],
setPassphrase = _React$useState4[1]; setPassphrase = _React$useState4[1];
var history = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_6__.useHistory)(); var history = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_7__.useHistory)();
var _React$useState5 = react__WEBPACK_IMPORTED_MODULE_3__.useState(checkPassphrase()), var _React$useState5 = react__WEBPACK_IMPORTED_MODULE_3__.useState(checkPassphrase()),
_React$useState6 = _slicedToArray(_React$useState5, 2), _React$useState6 = _slicedToArray(_React$useState5, 2),
@ -36192,16 +36577,16 @@ function App() {
var Error = function Error() { var Error = function Error() {
if (error) { if (error) {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], {
severity: "error" severity: "error"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], null, "Erreur"), "La phrase de passe ne correspond pas."); }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], null, "Erreur"), "La phrase de passe ne correspond pas.");
} }
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", null); return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", null);
}; };
var LoadButton = function LoadButton() { var LoadButton = function LoadButton() {
return allLoaded ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react__WEBPACK_IMPORTED_MODULE_3__.Fragment, null) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { return allLoaded ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react__WEBPACK_IMPORTED_MODULE_3__.Fragment, null) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], {
variant: "outlined", variant: "outlined",
size: "small", size: "small",
sx: { sx: {
@ -36214,8 +36599,8 @@ function App() {
}; };
var AuthButton = function AuthButton() { var AuthButton = function AuthButton() {
var history = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_6__.useHistory)(); var history = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_7__.useHistory)();
return user ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("p", null, "Bienvenue !", " ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { return user ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("p", null, "Bienvenue !", " ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], {
variant: "outlined", variant: "outlined",
size: "small", size: "small",
sx: { sx: {
@ -36226,7 +36611,7 @@ function App() {
return history.push("/diary/public"); return history.push("/diary/public");
}); });
} }
}, "Fermer mon carnet \xE0 clef")) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("p", null, "Votre carnet est ferm\xE9.", " ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_10__.Link, { }, "Fermer mon carnet \xE0 clef")) : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("p", null, "Votre carnet est ferm\xE9.", " ", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_11__.Link, {
to: "/diary/public/pages" to: "/diary/public/pages"
}, "Voir vos pages")); }, "Voir vos pages"));
}; };
@ -36251,10 +36636,10 @@ function App() {
var children = _a.children, var children = _a.children,
rest = __rest(_a, ["children"]); rest = __rest(_a, ["children"]);
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_6__.Route, Object.assign({}, rest, { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_7__.Route, Object.assign({}, rest, {
render: function render(_ref) { render: function render(_ref) {
var location = _ref.location; var location = _ref.location;
return user ? children : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_6__.Redirect, { return user ? children : /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_7__.Redirect, {
to: { to: {
pathname: "/diary/public/pass", pathname: "/diary/public/pass",
state: { state: {
@ -36273,10 +36658,40 @@ function App() {
}); });
} }
function getCalendarValuesFromPagesList(pages) {
return pages.map(function (page) {
var _page$date$split = page.date.split(" "),
_page$date$split2 = _slicedToArray(_page$date$split, 1),
date = _page$date$split2[0];
var splittedDate = date.split("/").map(function (part) {
return parseInt(part, 10);
});
return {
id: page.id,
date: new Date(splittedDate[2], splittedDate[1] - 1, splittedDate[0]),
event: page.id
};
});
}
function ListPage() { function ListPage() {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", {
className: "col-md-12" className: "col-md-12"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_List__WEBPACK_IMPORTED_MODULE_1__["default"], { }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_calendar_CalendarHeatmap__WEBPACK_IMPORTED_MODULE_6__["default"], {
values: getCalendarValuesFromPagesList(listPages),
startDate: startDate,
endDate: new Date(),
showMonthLabels: true,
showWeekdayLabels: true,
showOutOfRangeDays: true,
horizontal: true,
gutterSize: 4,
onClick: function onClick(value) {
return alert(value);
},
tooltipDataAttrs: {}
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_List__WEBPACK_IMPORTED_MODULE_1__["default"], {
pages: listPages, pages: listPages,
url: getPageContentUrl, url: getPageContentUrl,
passphrase: passphrase, passphrase: passphrase,
@ -36284,7 +36699,7 @@ function App() {
removeUrl: removeUrl, removeUrl: removeUrl,
loadPages: loadPages, loadPages: loadPages,
setAllLoaded: setAllLoaded setAllLoaded: setAllLoaded
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_Form__WEBPACK_IMPORTED_MODULE_0__["default"], { }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_Form__WEBPACK_IMPORTED_MODULE_0__["default"], {
setListPages: setListPages, setListPages: setListPages,
csrf: csrf, csrf: csrf,
url: postUrl, url: postUrl,
@ -36292,20 +36707,20 @@ function App() {
})); }));
} }
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(AuthButton, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(LoadButton, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(Error, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(AuthButton, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(LoadButton, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(Error, null), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], {
sx: { sx: {
height: "20px", height: "20px",
mb: "20px", mb: "20px",
mt: "10px" mt: "10px"
} }
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_6__.Switch, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_6__.Route, { }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_7__.Switch, null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(react_router_dom__WEBPACK_IMPORTED_MODULE_7__.Route, {
path: "/diary/public/pass" path: "/diary/public/pass"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(PromptPage, null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(PrivateRoute, { }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(PromptPage, null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(PrivateRoute, {
path: "/diary/public/pages" path: "/diary/public/pages"
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(ListPage, null)))); }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(ListPage, null))));
} }
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_router_dom__WEBPACK_IMPORTED_MODULE_6__.withRouter)(App)); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,react_router_dom__WEBPACK_IMPORTED_MODULE_7__.withRouter)(App));
/***/ }), /***/ }),
@ -36542,6 +36957,10 @@ function PageForm(_ref) {
})); }));
}; };
function updateContent(value) {
setContent(value);
}
if (isPassphraseSet) { if (isPassphraseSet) {
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement("form", { return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement("form", {
action: url, action: url,
@ -36559,7 +36978,7 @@ function PageForm(_ref) {
size: "small" size: "small"
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement(_uiw_react_md_editor__WEBPACK_IMPORTED_MODULE_3__["default"], { }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement(_uiw_react_md_editor__WEBPACK_IMPORTED_MODULE_3__["default"], {
value: content, value: content,
onChange: setContent onChange: updateContent
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], {
variant: "contained", variant: "contained",
type: "submit" type: "submit"
@ -37435,7 +37854,12 @@ function MobileMenu(_ref) {
"use strict"; "use strict";
__webpack_require__.r(__webpack_exports__); __webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "isAllLoadedLocally": () => (/* binding */ isAllLoadedLocally) /* harmony export */ "isAllLoadedLocally": () => (/* binding */ isAllLoadedLocally),
/* harmony export */ "shiftDate": () => (/* binding */ shiftDate),
/* harmony export */ "getBeginningTimeForDate": () => (/* binding */ getBeginningTimeForDate),
/* harmony export */ "convertToDate": () => (/* binding */ convertToDate),
/* harmony export */ "dateNDaysAgo": () => (/* binding */ dateNDaysAgo),
/* harmony export */ "getRange": () => (/* binding */ getRange)
/* harmony export */ }); /* harmony export */ });
var isAllLoadedLocally = function isAllLoadedLocally(pages) { var isAllLoadedLocally = function isAllLoadedLocally(pages) {
for (var i in pages) { for (var i in pages) {
@ -37448,6 +37872,40 @@ var isAllLoadedLocally = function isAllLoadedLocally(pages) {
return true; return true;
}; };
/** CALENDAR **/
// returns a new date shifted a certain number of days (can be negative)
var shiftDate = function shiftDate(date, numDays) {
var newDate = new Date(date);
newDate.setDate(newDate.getDate() + numDays);
return newDate;
};
var getBeginningTimeForDate = function getBeginningTimeForDate(date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}; // obj can be a parseable string, a millisecond timestamp, or a Date object
var convertToDate = function convertToDate(obj) {
return obj instanceof Date ? obj : new Date(obj);
};
var dateNDaysAgo = function dateNDaysAgo(numDaysAgo) {
return shiftDate(new Date(), -numDaysAgo);
};
var getRange = function getRange(count) {
var arr = [];
for (var idx = 0; idx < count; idx += 1) {
arr.push(idx);
}
return arr;
};
/** END CALENDAR **/
@ -37487,6 +37945,28 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
// forceTLS: true // forceTLS: true
// }); // });
/***/ }),
/***/ "./resources/js/components/calendar/constants.js":
/*!*******************************************************!*\
!*** ./resources/js/components/calendar/constants.js ***!
\*******************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "MILLISECONDS_IN_ONE_DAY": () => (/* binding */ MILLISECONDS_IN_ONE_DAY),
/* harmony export */ "DAYS_IN_WEEK": () => (/* binding */ DAYS_IN_WEEK),
/* harmony export */ "MONTH_LABELS": () => (/* binding */ MONTH_LABELS),
/* harmony export */ "DAY_LABELS": () => (/* binding */ DAY_LABELS)
/* harmony export */ });
var MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
var DAYS_IN_WEEK = 7;
var MONTH_LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var DAY_LABELS = ['', 'Mon', '', 'Wed', '', 'Fri', ''];
/***/ }), /***/ }),
/***/ "./node_modules/boolbase/index.js": /***/ "./node_modules/boolbase/index.js":

79
resources/css/app.css vendored
View File

@ -1,3 +1,82 @@
@import 'tailwindcss/base'; @import 'tailwindcss/base';
@import 'tailwindcss/components'; @import 'tailwindcss/components';
@import 'tailwindcss/utilities'; @import 'tailwindcss/utilities';
/*
* react-calendar-heatmap styles
*
* All of the styles in this file are optional and configurable!
* The github and gitlab color scales are provided for reference.
*/
@media all and (max-width: 768px) {
svg.react-calendar-heatmap {
transform: rotate(90deg);
}
}
.react-calendar-heatmap text {
font-size: 10px;
fill: #aaa;
}
.react-calendar-heatmap .react-calendar-heatmap-small-text {
font-size: 5px;
}
.react-calendar-heatmap rect:hover {
stroke: #555;
stroke-width: 1px;
}
/*
* Default color scale
*/
.react-calendar-heatmap .color-empty {
fill: #eeeeee;
}
.react-calendar-heatmap .color-filled {
fill: #8cc665;
}
/*
* Github color scale
*/
.react-calendar-heatmap .color-github-0 {
fill: #eeeeee;
}
.react-calendar-heatmap .color-github-1 {
fill: #d6e685;
}
.react-calendar-heatmap .color-github-2 {
fill: #8cc665;
}
.react-calendar-heatmap .color-github-3 {
fill: #44a340;
}
.react-calendar-heatmap .color-github-4 {
fill: #1e6823;
}
/*
* Gitlab color scale
*/
.react-calendar-heatmap .color-gitlab-0 {
fill: #ededed;
}
.react-calendar-heatmap .color-gitlab-1 {
fill: #acd5f2;
}
.react-calendar-heatmap .color-gitlab-2 {
fill: #7fa8d1;
}
.react-calendar-heatmap .color-gitlab-3 {
fill: #49729b;
}
.react-calendar-heatmap .color-gitlab-4 {
fill: #254e77;
}

View File

@ -0,0 +1,335 @@
import React from 'react';
import { DAYS_IN_WEEK, MILLISECONDS_IN_ONE_DAY, DAY_LABELS, MONTH_LABELS } from './constants.js';
import {
shiftDate,
getBeginningTimeForDate,
convertToDate,
getRange,
} from "../../utils";
import {CalendarHeatmapProp} from "./CalendarHeatmapProp";
const SQUARE_SIZE = 10;
const MONTH_LABEL_GUTTER_SIZE = 4;
const CSS_PSEUDO_NAMESPACE = 'react-calendar-heatmap-';
function CalendarHeatmap({
values, startDate, endDate, gutterSize, horizontal,
showMonthLabels, showWeekdayLabels, showOutOfRangeDays, tooltipDataAttrs,
onClick, onMouseOver, onMouseLeave, transformDayElement
}: CalendarHeatmapProp) {
const cachedValues = {};
for (const i in values) {
const value = values[i];
const date = convertToDate(value.date);
const index = Math.floor((date.getTime() - getStartDateWithEmptyDays().getTime()) / MILLISECONDS_IN_ONE_DAY);
cachedValues[index] = {
date: value.date,
event: value.event,
className: classForValue(value.id),
title: titleForValue(value.id),
tooltipDataAttrs: getTooltipDataAttrsForValue(value.id),
};
}
function getDateDifferenceInDays() {
const timeDiff = getEndDate().getTime() - convertToDate(startDate).getTime();
return Math.ceil(timeDiff / MILLISECONDS_IN_ONE_DAY);
}
function classForValue(value) {
return value ? 'color-filled' : 'color-empty';
}
function titleForValue(value) {
return value;
}
function getSquareSizeWithGutter() {
return SQUARE_SIZE + gutterSize;
}
function getMonthLabelSize() {
if (!showMonthLabels) {
return 0;
}
if (horizontal) {
return SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE;
}
return 2 * (SQUARE_SIZE + MONTH_LABEL_GUTTER_SIZE);
}
function getWeekdayLabelSize() {
if (!showWeekdayLabels) {
return 0;
}
if (horizontal) {
return 30;
}
return SQUARE_SIZE * 1.5;
}
function getStartDate() {
return shiftDate(getEndDate(), -getDateDifferenceInDays() + 1); // +1 because endDate is inclusive
}
function getEndDate(): Date {
return getBeginningTimeForDate(convertToDate(endDate));
}
function getStartDateWithEmptyDays() {
return shiftDate(getStartDate(), -getNumEmptyDaysAtStart());
}
function getNumEmptyDaysAtStart() {
return getStartDate().getDay();
}
function getNumEmptyDaysAtEnd() {
return DAYS_IN_WEEK - 1 - getEndDate().getDay();
}
function getWeekCount() {
const numDaysRoundedToWeek =
getDateDifferenceInDays() + getNumEmptyDaysAtStart() + getNumEmptyDaysAtEnd();
return Math.ceil(numDaysRoundedToWeek / DAYS_IN_WEEK);
}
function getWeekWidth() {
return DAYS_IN_WEEK * getSquareSizeWithGutter();
}
function getWidth() {
return (
getWeekCount() * getSquareSizeWithGutter() -
(gutterSize - getWeekdayLabelSize())
);
}
function getHeight() {
return (
getWeekWidth() +
(getMonthLabelSize() - gutterSize) +
getWeekdayLabelSize()
);
}
function getValueForIndex(index) {
if (cachedValues[index]) {
console.log(index, cachedValues);
return cachedValues[index].event;
}
return null;
}
function getClassNameForIndex(index) {
if (cachedValues[index]) {
return cachedValues[index].className;
}
return classForValue(null);
}
function getTitleForIndex(index) {
if (cachedValues[index]) {
return cachedValues[index].title;
}
return titleForValue ? titleForValue(null) : null;
}
function getTooltipDataAttrsForIndex(index) {
if (cachedValues[index]) {
return cachedValues[index].tooltipDataAttrs;
}
return getTooltipDataAttrsForValue({ date: null, count: null });
}
function getTooltipDataAttrsForValue(value) {
if (typeof tooltipDataAttrs === 'function') {
return tooltipDataAttrs(value);
}
return tooltipDataAttrs;
}
function getTransformForWeek(weekIndex) {
if (horizontal) {
return `translate(${weekIndex * getSquareSizeWithGutter()}, 0)`;
}
return `translate(0, ${weekIndex * getSquareSizeWithGutter()})`;
}
function getTransformForWeekdayLabels() {
if (horizontal) {
return `translate(${SQUARE_SIZE}, ${getMonthLabelSize()})`;
}
return "";
}
function getTransformForMonthLabels() {
if (horizontal) {
return `translate(${getWeekdayLabelSize()}, 0)`;
}
return `translate(${getWeekWidth() + MONTH_LABEL_GUTTER_SIZE}, ${getWeekdayLabelSize()})`;
}
function getTransformForAllWeeks() {
if (horizontal) {
return `translate(${getWeekdayLabelSize()}, ${getMonthLabelSize()})`;
}
return `translate(0, ${getWeekdayLabelSize()})`;
}
function getViewBox() {
if (horizontal) {
return `0 0 ${getWidth()} ${getHeight()}`;
}
return `0 0 ${getHeight()} ${getWidth()}`;
}
function getSquareCoordinates(dayIndex) {
if (horizontal) {
return [0, dayIndex * getSquareSizeWithGutter()];
}
return [dayIndex * getSquareSizeWithGutter(), 0];
}
function getWeekdayLabelCoordinates(dayIndex) {
if (horizontal) {
return [0, (dayIndex + 1) * SQUARE_SIZE + dayIndex * gutterSize];
}
return [dayIndex * SQUARE_SIZE + dayIndex * gutterSize, SQUARE_SIZE];
}
function getMonthLabelCoordinates(weekIndex) {
if (horizontal) {
return [
weekIndex * getSquareSizeWithGutter(),
getMonthLabelSize() - MONTH_LABEL_GUTTER_SIZE,
];
}
const verticalOffset = -2;
return [0, (weekIndex + 1) * getSquareSizeWithGutter() + verticalOffset];
}
function handleClick(value) {
if (onClick) {
onClick(value);
}
}
function handleMouseOver(e, value) {
if (onMouseOver) {
onMouseOver(e, value);
}
}
function handleMouseLeave(e, value) {
if (onMouseLeave) {
onMouseLeave(e, value);
}
}
function renderSquare(dayIndex, index) {
const indexOutOfRange =
index < getNumEmptyDaysAtStart() ||
index >= getNumEmptyDaysAtStart() + getDateDifferenceInDays();
if (indexOutOfRange && !showOutOfRangeDays) {
return null;
}
const [x, y] = getSquareCoordinates(dayIndex);
const value = getValueForIndex(index);
const rect = (
<rect
key={index}
width={SQUARE_SIZE}
height={SQUARE_SIZE}
x={x}
y={y}
className={getClassNameForIndex(index)}
onClick={() => handleClick(value)}
onMouseOver={(e) => handleMouseOver(e, value)}
onMouseLeave={(e) => handleMouseLeave(e, value)}
{...getTooltipDataAttrsForIndex(index)}
>
<title>{getTitleForIndex(index)}</title>
</rect>
);
return transformDayElement ? transformDayElement(rect, value as string, index) : rect;
}
function renderWeek(weekIndex) {
return (
<g
key={weekIndex}
transform={getTransformForWeek(weekIndex)}
className={`${CSS_PSEUDO_NAMESPACE}week`}
>
{getRange(DAYS_IN_WEEK).map((dayIndex) =>
renderSquare(dayIndex, weekIndex * DAYS_IN_WEEK + dayIndex),
)}
</g>
);
}
function renderAllWeeks() {
return getRange(getWeekCount()).map((weekIndex) => renderWeek(weekIndex));
}
function renderMonthLabels() {
if (!showMonthLabels) {
return null;
}
const weekRange = getRange(getWeekCount() - 1); // don't render for last week, because label will be cut off
return weekRange.map((weekIndex) => {
const endOfWeek = shiftDate(getStartDateWithEmptyDays(), (weekIndex + 1) * DAYS_IN_WEEK);
const [x, y] = getMonthLabelCoordinates(weekIndex);
return endOfWeek.getDate() >= 1 && endOfWeek.getDate() <= DAYS_IN_WEEK ? (
<text key={weekIndex} x={x} y={y} className={`${CSS_PSEUDO_NAMESPACE}month-label`}>
{MONTH_LABELS[endOfWeek.getMonth()]}
</text>
) : null;
});
}
function renderWeekdayLabels() {
if (!showWeekdayLabels) {
return null;
}
return DAY_LABELS.map((weekdayLabel, dayIndex) => {
const [x, y] = getWeekdayLabelCoordinates(dayIndex);
const cssClasses = `${
horizontal ? '' : `${CSS_PSEUDO_NAMESPACE}small-text`
} ${CSS_PSEUDO_NAMESPACE}weekday-label`;
// eslint-disable-next-line no-bitwise
return dayIndex & 1 ? (
<text key={`${x}${y}`} x={x} y={y} className={cssClasses}>
{weekdayLabel}
</text>
) : null;
});
}
return (
<svg className="react-calendar-heatmap" viewBox={getViewBox()}>
<g
transform={getTransformForMonthLabels()}
className={`${CSS_PSEUDO_NAMESPACE}month-labels`}
>
{renderMonthLabels()}
</g>
<g
transform={getTransformForAllWeeks()}
className={`${CSS_PSEUDO_NAMESPACE}all-weeks`}
>
{renderAllWeeks()}
</g>
<g
transform={getTransformForWeekdayLabels()}
className={`${CSS_PSEUDO_NAMESPACE}weekday-labels`}
>
{renderWeekdayLabels()}
</g>
</svg>
);
}
export default CalendarHeatmap;

View File

@ -0,0 +1,19 @@
import {CalendarHeatmapValuesProp} from "./CalendarHeatmapValuesProp";
import {ReactEventHandler} from "react";
export interface CalendarHeatmapProp {
values: CalendarHeatmapValuesProp[]; // array of objects with date and arbitrary metadata
startDate: Date; // start of date range
endDate: Date; // end of date range
gutterSize: number; // size of space between squares
horizontal: boolean; // whether to orient horizontally or vertically
showMonthLabels: boolean; // whether to show month labels
showWeekdayLabels: boolean; // whether to show weekday labels
showOutOfRangeDays: boolean; // whether to render squares for extra days in week after endDate, and before start date
tooltipDataAttrs: object; // data attributes to add to square for setting 3rd party tooltips, e.g. { 'data-toggle': 'tooltip' } for bootstrap tooltips
onClick: (v:string) => void; // callback function when a square is clicked
onMouseOver?: (e:ReactEventHandler, v:string) => void; // callback function when mouse pointer is over a square
onMouseLeave?: (e:ReactEventHandler, v:string) => void; // callback function when mouse pointer is left a square
transformDayElement?: (element:JSX.Element, v:string, i:number) => void; // function to further transform the svg element for a single day
}

View File

@ -0,0 +1,5 @@
export interface CalendarHeatmapValuesProp {
id: string;
date: Date;
event: string;
}

View File

@ -0,0 +1,22 @@
const MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
const DAYS_IN_WEEK = 7;
const MONTH_LABELS = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const DAY_LABELS = ['', 'Mon', '', 'Wed', '', 'Fri', ''];
export { MILLISECONDS_IN_ONE_DAY, DAYS_IN_WEEK, MONTH_LABELS, DAY_LABELS };

View File

@ -14,6 +14,8 @@ import {
} from "react-router-dom"; } from "react-router-dom";
import {IList} from "../../interfaces/IList"; import {IList} from "../../interfaces/IList";
import {isAllLoadedLocally} from "../../utils"; import {isAllLoadedLocally} from "../../utils";
import CalendarHeatmap from "../calendar/CalendarHeatmap";
import {CalendarHeatmapValuesProp} from "../calendar/CalendarHeatmapValuesProp";
const app = document.getElementById('app'); const app = document.getElementById('app');
const word = "shikiryu"; // FIXME should be in db and ≠ between users const word = "shikiryu"; // FIXME should be in db and ≠ between users
@ -24,12 +26,14 @@ let getPageContentUrl,
postUrl, postUrl,
removeUrl, removeUrl,
checkword, checkword,
startDate,
csrf = ""; csrf = "";
if (app) { if (app) {
getPageContentUrl = "" + app.getAttribute('data-url'); getPageContentUrl = "" + app.getAttribute('data-url');
pages = JSON.parse("" + app.getAttribute('data-list')) as IList[]; pages = JSON.parse("" + app.getAttribute('data-list')) as IList[];
postUrl = "" + app.getAttribute('data-post'); postUrl = "" + app.getAttribute('data-post');
startDate = "" + app.getAttribute('data-start');
removeUrl = "" + app.getAttribute('data-remove'); removeUrl = "" + app.getAttribute('data-remove');
csrf = "" + app.getAttribute('data-csrf'); csrf = "" + app.getAttribute('data-csrf');
checkword = "" + app.getAttribute('data-checkword'); checkword = "" + app.getAttribute('data-checkword');
@ -157,9 +161,33 @@ function App() {
return (<Prompt open={true} setOpen={updatePassphrase}/>); return (<Prompt open={true} setOpen={updatePassphrase}/>);
} }
function getCalendarValuesFromPagesList(pages: IList[]): CalendarHeatmapValuesProp[] {
return pages.map(page => {
const [date, ] = page.date.split(" ");
const splittedDate = date.split("/").map(part => { return parseInt(part, 10);});
return {
id: page.id,
date: new Date(splittedDate[2] as number, splittedDate[1] - 1, splittedDate[0] as number),
event: page.id
};
});
}
function ListPage() { function ListPage() {
return ( return (
<div className="col-md-12"> <div className="col-md-12">
<CalendarHeatmap
values={getCalendarValuesFromPagesList(listPages)}
startDate={startDate}
endDate={new Date()}
showMonthLabels={true}
showWeekdayLabels={true}
showOutOfRangeDays={true}
horizontal={true}
gutterSize={4}
onClick={(value) => alert(value)}
tooltipDataAttrs={{}}
/>
<Pages <Pages
pages={listPages} pages={listPages}
url={getPageContentUrl} url={getPageContentUrl}

View File

@ -6,7 +6,7 @@ let encryptStorage = new EncryptStorage('test'); // TODO la clef doit venir de l
export default function PageForm({setListPages, csrf, url, passphrase}) { export default function PageForm({setListPages, csrf, url, passphrase}) {
const isPassphraseSet = passphrase !== null; const isPassphraseSet = passphrase !== null;
const [content, setContent] = React.useState(""); const [content, setContent] = React.useState<string>("");
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => { const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault(); event.preventDefault();
encryptStorage = new EncryptStorage(passphrase); encryptStorage = new EncryptStorage(passphrase);
@ -56,6 +56,9 @@ export default function PageForm({setListPages, csrf, url, passphrase}) {
]); ]);
} }
} }
function updateContent(value: string|undefined): void {
setContent(value as string);
}
if (isPassphraseSet) { if (isPassphraseSet) {
return ( return (
@ -73,7 +76,7 @@ export default function PageForm({setListPages, csrf, url, passphrase}) {
/> />
<MDEditor <MDEditor
value={content} value={content}
onChange={setContent} onChange={updateContent}
/> />
<Button variant="contained" type={"submit"}> <Button variant="contained" type={"submit"}>
Enregistrer Enregistrer

View File

@ -11,4 +11,36 @@ const isAllLoadedLocally = function(pages: IList[]) {
return true; return true;
} }
export { isAllLoadedLocally }; /** CALENDAR **/
// returns a new date shifted a certain number of days (can be negative)
const shiftDate = function(date, numDays) {
const newDate = new Date(date);
newDate.setDate(newDate.getDate() + numDays);
return newDate;
}
const getBeginningTimeForDate = function(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
// obj can be a parseable string, a millisecond timestamp, or a Date object
const convertToDate = function(obj): Date {
return obj instanceof Date ? obj : new Date(obj);
}
const dateNDaysAgo = function(numDaysAgo) {
return shiftDate(new Date(), -numDaysAgo);
}
const getRange = function(count) {
const arr: number[] = [];
for (let idx = 0; idx < count; idx += 1) {
arr.push(idx);
}
return arr;
}
/** END CALENDAR **/
export { isAllLoadedLocally, shiftDate, getBeginningTimeForDate, convertToDate, dateNDaysAgo, getRange };

View File

@ -10,6 +10,7 @@
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200"> <div class="p-6 bg-white border-b border-gray-200">
<div id="app" <div id="app"
data-start="{{ $start_date->format('Y-m-d') }}"
data-list="{{json_encode($pages)}}" data-list="{{json_encode($pages)}}"
data-url="{{ route('pages.show', ['page' => 'replace_me']) }}" data-url="{{ route('pages.show', ['page' => 'replace_me']) }}"
data-post="{{ route('pages.store') }}" data-post="{{ route('pages.store') }}"