🚧 Commence l'ajout de calendrier
This commit is contained in:
parent
e1f2294fe4
commit
d7442355dc
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@ -47,6 +48,7 @@ class PageController extends Controller
|
||||
$user = Auth::user();
|
||||
|
||||
return view('pages.index', [
|
||||
'start_date'=> min((new DateTime())->sub(new DateInterval('P1Y')), $user->created_at),
|
||||
'checkword' => $user->checkword,
|
||||
'pages' => $pages,
|
||||
]);
|
||||
|
67
public/css/app.css
vendored
67
public/css/app.css
vendored
@ -12385,6 +12385,73 @@ select {
|
||||
.ease-in {
|
||||
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 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
||||
|
524
public/js/app.js
vendored
524
public/js/app.js
vendored
@ -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 ***!
|
||||
@ -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 _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 _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/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_11__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/Divider/Divider.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_9__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/AlertTitle/AlertTitle.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_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___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_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_7__ = __webpack_require__(/*! react-router-dom */ "./node_modules/react-router/esm/react-router.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 _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 _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 word = "shikiryu"; // FIXME should be in db and ≠ between users
|
||||
|
||||
@ -36110,12 +36493,14 @@ var getPageContentUrl,
|
||||
postUrl,
|
||||
removeUrl,
|
||||
checkword,
|
||||
startDate,
|
||||
csrf = "";
|
||||
|
||||
if (app) {
|
||||
getPageContentUrl = "" + app.getAttribute('data-url');
|
||||
pages = JSON.parse("" + app.getAttribute('data-list'));
|
||||
postUrl = "" + app.getAttribute('data-post');
|
||||
startDate = "" + app.getAttribute('data-start');
|
||||
removeUrl = "" + app.getAttribute('data-remove');
|
||||
csrf = "" + app.getAttribute('data-csrf');
|
||||
checkword = "" + app.getAttribute('data-checkword');
|
||||
@ -36132,7 +36517,7 @@ function App() {
|
||||
passphrase = _React$useState4[0],
|
||||
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()),
|
||||
_React$useState6 = _slicedToArray(_React$useState5, 2),
|
||||
@ -36192,16 +36577,16 @@ function App() {
|
||||
|
||||
var Error = function 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"
|
||||
}, /*#__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);
|
||||
};
|
||||
|
||||
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",
|
||||
size: "small",
|
||||
sx: {
|
||||
@ -36214,8 +36599,8 @@ function App() {
|
||||
};
|
||||
|
||||
var AuthButton = function AuthButton() {
|
||||
var history = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_6__.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"], {
|
||||
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_10__["default"], {
|
||||
variant: "outlined",
|
||||
size: "small",
|
||||
sx: {
|
||||
@ -36226,7 +36611,7 @@ function App() {
|
||||
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"
|
||||
}, "Voir vos pages"));
|
||||
};
|
||||
@ -36251,10 +36636,10 @@ function App() {
|
||||
var children = _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) {
|
||||
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: {
|
||||
pathname: "/diary/public/pass",
|
||||
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() {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement("div", {
|
||||
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,
|
||||
url: getPageContentUrl,
|
||||
passphrase: passphrase,
|
||||
@ -36284,7 +36699,7 @@ function App() {
|
||||
removeUrl: removeUrl,
|
||||
loadPages: loadPages,
|
||||
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,
|
||||
csrf: csrf,
|
||||
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: {
|
||||
height: "20px",
|
||||
mb: "20px",
|
||||
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"
|
||||
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(PromptPage, null)), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_3__.createElement(PrivateRoute, {
|
||||
path: "/diary/public/pages"
|
||||
}, /*#__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) {
|
||||
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement("form", {
|
||||
action: url,
|
||||
@ -36559,7 +36978,7 @@ function PageForm(_ref) {
|
||||
size: "small"
|
||||
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement(_uiw_react_md_editor__WEBPACK_IMPORTED_MODULE_3__["default"], {
|
||||
value: content,
|
||||
onChange: setContent
|
||||
onChange: updateContent
|
||||
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__.createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], {
|
||||
variant: "contained",
|
||||
type: "submit"
|
||||
@ -37435,7 +37854,12 @@ function MobileMenu(_ref) {
|
||||
"use strict";
|
||||
__webpack_require__.r(__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 */ });
|
||||
var isAllLoadedLocally = function isAllLoadedLocally(pages) {
|
||||
for (var i in pages) {
|
||||
@ -37448,6 +37872,40 @@ var isAllLoadedLocally = function isAllLoadedLocally(pages) {
|
||||
|
||||
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
|
||||
// });
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ "./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":
|
||||
|
79
resources/css/app.css
vendored
79
resources/css/app.css
vendored
@ -1,3 +1,82 @@
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@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;
|
||||
}
|
||||
|
335
resources/js/components/calendar/CalendarHeatmap.tsx
Normal file
335
resources/js/components/calendar/CalendarHeatmap.tsx
Normal 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;
|
19
resources/js/components/calendar/CalendarHeatmapProp.ts
Normal file
19
resources/js/components/calendar/CalendarHeatmapProp.ts
Normal 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
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
export interface CalendarHeatmapValuesProp {
|
||||
id: string;
|
||||
date: Date;
|
||||
event: string;
|
||||
}
|
22
resources/js/components/calendar/constants.js
vendored
Normal file
22
resources/js/components/calendar/constants.js
vendored
Normal 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 };
|
@ -14,6 +14,8 @@ import {
|
||||
} from "react-router-dom";
|
||||
import {IList} from "../../interfaces/IList";
|
||||
import {isAllLoadedLocally} from "../../utils";
|
||||
import CalendarHeatmap from "../calendar/CalendarHeatmap";
|
||||
import {CalendarHeatmapValuesProp} from "../calendar/CalendarHeatmapValuesProp";
|
||||
|
||||
const app = document.getElementById('app');
|
||||
const word = "shikiryu"; // FIXME should be in db and ≠ between users
|
||||
@ -24,12 +26,14 @@ let getPageContentUrl,
|
||||
postUrl,
|
||||
removeUrl,
|
||||
checkword,
|
||||
startDate,
|
||||
csrf = "";
|
||||
|
||||
if (app) {
|
||||
getPageContentUrl = "" + app.getAttribute('data-url');
|
||||
pages = JSON.parse("" + app.getAttribute('data-list')) as IList[];
|
||||
postUrl = "" + app.getAttribute('data-post');
|
||||
startDate = "" + app.getAttribute('data-start');
|
||||
removeUrl = "" + app.getAttribute('data-remove');
|
||||
csrf = "" + app.getAttribute('data-csrf');
|
||||
checkword = "" + app.getAttribute('data-checkword');
|
||||
@ -157,9 +161,33 @@ function App() {
|
||||
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() {
|
||||
return (
|
||||
<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={listPages}
|
||||
url={getPageContentUrl}
|
||||
|
@ -6,7 +6,7 @@ let encryptStorage = new EncryptStorage('test'); // TODO la clef doit venir de l
|
||||
|
||||
export default function PageForm({setListPages, csrf, url, passphrase}) {
|
||||
const isPassphraseSet = passphrase !== null;
|
||||
const [content, setContent] = React.useState("");
|
||||
const [content, setContent] = React.useState<string>("");
|
||||
const onSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
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) {
|
||||
return (
|
||||
@ -73,7 +76,7 @@ export default function PageForm({setListPages, csrf, url, passphrase}) {
|
||||
/>
|
||||
<MDEditor
|
||||
value={content}
|
||||
onChange={setContent}
|
||||
onChange={updateContent}
|
||||
/>
|
||||
<Button variant="contained" type={"submit"}>
|
||||
Enregistrer
|
||||
|
@ -11,4 +11,36 @@ const isAllLoadedLocally = function(pages: IList[]) {
|
||||
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 };
|
||||
|
@ -10,6 +10,7 @@
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 bg-white border-b border-gray-200">
|
||||
<div id="app"
|
||||
data-start="{{ $start_date->format('Y-m-d') }}"
|
||||
data-list="{{json_encode($pages)}}"
|
||||
data-url="{{ route('pages.show', ['page' => 'replace_me']) }}"
|
||||
data-post="{{ route('pages.store') }}"
|
||||
|
Loading…
Reference in New Issue
Block a user