Compare commits

...
Sign in to create a new pull request.

1 commit
main ... test

Author SHA1 Message Date
835832c474 test? 2022-04-28 17:04:04 -04:00
86 changed files with 8267 additions and 11856 deletions

13
.idea/.idea.App/.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,13 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/.idea.App.iml
/modules.xml
/projectSettingsUpdater.xml
/contentModel.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.idea.App/.idea/.name generated Normal file
View file

@ -0,0 +1 @@
App

4
.idea/.idea.App/.idea/encodings.xml generated Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

8
.idea/.idea.App/.idea/indexLayout.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

6
.idea/.idea.App/.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

19
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}",
"skipFiles": [
"<node_internals>/**",
"**/node_modules/**"
]
}
]
}

View file

@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
webpack.common.js = webpack.common.js
webpack.config.js = webpack.config.js
webpack.tests.js = webpack.tests.js
tailwind-process.js = tailwind-process.js
EndProjectSection
EndProject
Global

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,010 B

12
content/index.html Normal file
View file

@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<title>FableTailwind</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="fable.ico" />
</head>
<body>
<div id="feliz-app"></div>
</body>
</html>

View file

@ -0,0 +1,549 @@
/*
! tailwindcss v3.0.7 | MIT License | https://tailwindcss.com
*/
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box;
/* 1 */
border-width: 0;
/* 2 */
border-style: solid;
/* 2 */
border-color: currentColor;
/* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
*/
html {
line-height: 1.5;
/* 1 */
-webkit-text-size-adjust: 100%;
/* 2 */
-moz-tab-size: 4;
/* 3 */
-o-tab-size: 4;
tab-size: 4;
/* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
/* 4 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0;
/* 1 */
line-height: inherit;
/* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0;
/* 1 */
color: inherit;
/* 2 */
border-top-width: 1px;
/* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0;
/* 1 */
border-color: inherit;
/* 2 */
border-collapse: collapse;
/* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 1 */
line-height: inherit;
/* 1 */
color: inherit;
/* 1 */
margin: 0;
/* 2 */
padding: 0;
/* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button;
/* 1 */
background-color: transparent;
/* 2 */
background-image: none;
/* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield;
/* 1 */
outline-offset: -2px;
/* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button;
/* 1 */
font: inherit;
/* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::-webkit-input-placeholder, textarea::-webkit-input-placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
input::placeholder,
textarea::placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
/* 1 */
vertical-align: middle;
/* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
Ensure the default browser behavior of the `hidden` attribute.
*/
[hidden] {
display: none;
}
*, ::before, ::after {
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-transform: translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
--tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: var(--tw-empty,/*!*/ /*!*/);
--tw-brightness: var(--tw-empty,/*!*/ /*!*/);
--tw-contrast: var(--tw-empty,/*!*/ /*!*/);
--tw-grayscale: var(--tw-empty,/*!*/ /*!*/);
--tw-hue-rotate: var(--tw-empty,/*!*/ /*!*/);
--tw-invert: var(--tw-empty,/*!*/ /*!*/);
--tw-saturate: var(--tw-empty,/*!*/ /*!*/);
--tw-sepia: var(--tw-empty,/*!*/ /*!*/);
--tw-drop-shadow: var(--tw-empty,/*!*/ /*!*/);
--tw-filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.container {
width: 100%;
}
@media (min-width: 640px) {
.container {
max-width: 640px;
}
}
@media (min-width: 768px) {
.container {
max-width: 768px;
}
}
@media (min-width: 1024px) {
.container {
max-width: 1024px;
}
}
@media (min-width: 1280px) {
.container {
max-width: 1280px;
}
}
@media (min-width: 1536px) {
.container {
max-width: 1536px;
}
}
/* Custom component classes: https://tailwindcss.com/docs/extracting-components/#extracting-css-components-with-apply */
.static {
position: static;
}
.fixed {
position: fixed;
}
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.inline {
display: inline;
}
.table {
display: table;
}
.contents {
display: contents;
}
.transform {
-webkit-transform: var(--tw-transform);
transform: var(--tw-transform);
}
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.\!truncate {
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
.rounded {
border-radius: 0.25rem;
}
.ring {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.filter {
-webkit-filter: var(--tw-filter);
filter: var(--tw-filter);
}

View file

@ -0,0 +1,21 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
/* Custom component classes: https://tailwindcss.com/docs/extracting-components/#extracting-css-components-with-apply */
.custom-blue-button {
@apply bg-blue-500 text-white text-lg font-bold py-02 px-04 rounded-full border-2 border-blue-500
}
.custom-blue-button:hover {
@apply bg-blue-700
}
.custom-blue-button:focus {
@apply outline-none border-blue-700
}
}

2
dist/app.fa3660d8700d99b79340.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,32 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/** @license React v0.20.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

2
dist/app.feafe89237f721f4101d.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,32 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/** @license React v0.20.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.1
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

BIN
dist/favicon-16x16.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

BIN
dist/favicon-32x32.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,010 B

1
dist/index.html vendored Normal file
View file

@ -0,0 +1 @@
<!doctype html><html><head><title>FableTailwind</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="shortcut icon" href="fable.ico"/><script defer="defer" src="app.feafe89237f721f4101d.js"></script><link href="style.875744d132de81b1b971.css" rel="stylesheet"></head><body><div id="feliz-app"></div></body></html>

1
dist/style.0611ff27d83c1f550250.css vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/style.875744d132de81b1b971.css vendored Normal file
View file

@ -0,0 +1 @@
*,:after,:before{border:0 solid;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-transform:translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));--tw-blur:var(--tw-empty,/*!*/ /*!*/);--tw-brightness:var(--tw-empty,/*!*/ /*!*/);--tw-contrast:var(--tw-empty,/*!*/ /*!*/);--tw-grayscale:var(--tw-empty,/*!*/ /*!*/);--tw-hue-rotate:var(--tw-empty,/*!*/ /*!*/);--tw-invert:var(--tw-empty,/*!*/ /*!*/);--tw-saturate:var(--tw-empty,/*!*/ /*!*/);--tw-sepia:var(--tw-empty,/*!*/ /*!*/);--tw-drop-shadow:var(--tw-empty,/*!*/ /*!*/);--tw-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inline{display:inline}.table{display:table}.contents{display:contents}.transform{-webkit-transform:var(--tw-transform);transform:var(--tw-transform)}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.\!truncate{overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important}.rounded{border-radius:.25rem}.filter{-webkit-filter:var(--tw-filter);filter:var(--tw-filter)}

41
dist/tests/Tests.js vendored Normal file
View file

@ -0,0 +1,41 @@
import { Mocha_runTests, Test_testCase, Test_testList } from "./fable_modules/Fable.Mocha.2.9.1/Mocha.fs.js";
import { int32ToString, structuralHash, assertEqual } from "./fable_modules/fable-library.3.6.2/Util.js";
import { singleton, ofArray, contains } from "./fable_modules/fable-library.3.6.2/List.js";
import { equals, class_type, string_type, float64_type, bool_type, int32_type } from "./fable_modules/fable-library.3.6.2/Reflection.js";
import { printf, toText } from "./fable_modules/fable-library.3.6.2/String.js";
export function add(x, y) {
return x + y;
}
export const appTests = Test_testList("App tests", singleton(Test_testCase("add works", () => {
let copyOfStruct;
const actual = add(2, 3) | 0;
const expected = 5;
const msg = "Result must be 5";
if ((actual === expected) ? true : (!(new Function("try {return this===window;}catch(e){ return false;}"))())) {
assertEqual(actual, expected, msg);
}
else {
let errorMsg;
if (contains((copyOfStruct = actual, int32_type), ofArray([int32_type, bool_type, float64_type, string_type, class_type("System.Decimal"), class_type("System.Guid")]), {
Equals: (x, y) => equals(x, y),
GetHashCode: (x) => structuralHash(x),
})) {
const arg20 = int32ToString(actual);
const arg10 = int32ToString(expected);
errorMsg = toText(printf("\u003cspan style=\u0027color:black\u0027\u003eExpected:\u003c/span\u003e \u003cbr /\u003e\u003cdiv style=\u0027margin-left:20px; color:crimson\u0027\u003e%s\u003c/div\u003e\u003cbr /\u003e\u003cspan style=\u0027color:black\u0027\u003eActual:\u003c/span\u003e \u003c/br \u003e\u003cdiv style=\u0027margin-left:20px;color:crimson\u0027\u003e%s\u003c/div\u003e\u003cbr /\u003e\u003cspan style=\u0027color:black\u0027\u003eMessage:\u003c/span\u003e \u003c/br \u003e\u003cdiv style=\u0027margin-left:20px; color:crimson\u0027\u003e%s\u003c/div\u003e"))(arg10)(arg20)(msg);
}
else {
errorMsg = toText(printf("\u003cspan style=\u0027color:black\u0027\u003eExpected:\u003c/span\u003e \u003cbr /\u003e\u003cdiv style=\u0027margin-left:20px; color:crimson\u0027\u003e%A\u003c/div\u003e\u003cbr /\u003e\u003cspan style=\u0027color:black\u0027\u003eActual:\u003c/span\u003e \u003c/br \u003e\u003cdiv style=\u0027margin-left:20px;color:crimson\u0027\u003e%A\u003c/div\u003e\u003cbr /\u003e\u003cspan style=\u0027color:black\u0027\u003eMessage:\u003c/span\u003e \u003c/br \u003e\u003cdiv style=\u0027margin-left:20px; color:crimson\u0027\u003e%s\u003c/div\u003e"))(expected)(actual)(msg);
}
throw (new Error(errorMsg));
}
})));
export const allTests = Test_testList("All", singleton(appTests));
(function (args) {
return Mocha_runTests(allTests);
})(typeof process === 'object' ? process.argv.slice(2) : []);

18
dist/tests/src/Actions.js vendored Normal file
View file

@ -0,0 +1,18 @@
import { Union } from "../fable_modules/fable-library.3.6.2/Types.js";
import { union_type, class_type } from "../fable_modules/fable-library.3.6.2/Reflection.js";
export class Msg extends Union {
constructor(tag, ...fields) {
super();
this.tag = (tag | 0);
this.fields = fields;
}
cases() {
return ["ChangeDate"];
}
}
export function Msg$reflection() {
return union_type("App.Actions.Msg", [], Msg, () => [[["Item", class_type("System.DateTime")]]]);
}

48
dist/tests/src/Container.js vendored Normal file
View file

@ -0,0 +1,48 @@
import { Record } from "../fable_modules/fable-library.3.6.2/Types.js";
import { record_type, class_type } from "../fable_modules/fable-library.3.6.2/Reflection.js";
import { now } from "../fable_modules/fable-library.3.6.2/Date.js";
import { useReact_useReducer_2B9E6EA0 } from "../fable_modules/Feliz.1.57.0/React.fs.js";
import { createElement } from "react";
import { DatePicker } from "./DatePicker.js";
import { UserEntry } from "./UserEntry.js";
import { ofArray } from "../fable_modules/fable-library.3.6.2/List.js";
import { Interop_reactApi } from "../fable_modules/Feliz.1.57.0/Interop.fs.js";
export class State extends Record {
constructor(Date$) {
super();
this.Date = Date$;
}
}
export function State$reflection() {
return record_type("App.Container.State", [], State, () => [["Date", class_type("System.DateTime")]]);
}
export const initialState = new State(now());
export function update(state, _arg1) {
return new State(_arg1.fields[0]);
}
export function Container() {
let children;
const patternInput = useReact_useReducer_2B9E6EA0((state, _arg1) => update(state, _arg1), initialState);
const state_1 = patternInput[0];
const children_2 = ofArray([createElement(DatePicker, {
currentDate: state_1.Date,
updateDate: patternInput[1],
}), (children = ofArray([createElement(UserEntry, {
username: "a_mae_zing",
currentDate: state_1.Date,
}), createElement(UserEntry, {
username: "Anthony",
currentDate: state_1.Date,
})]), createElement("ol", {
children: Interop_reactApi.Children.toArray(Array.from(children)),
}))]);
return createElement("div", {
children: Interop_reactApi.Children.toArray(Array.from(children_2)),
});
}

20
dist/tests/src/DatePicker.js vendored Normal file
View file

@ -0,0 +1,20 @@
import { createElement } from "react";
import { createObj } from "../fable_modules/fable-library.3.6.2/Util.js";
import { toString } from "../fable_modules/fable-library.3.6.2/Date.js";
import { iterate } from "../fable_modules/fable-library.3.6.2/Seq.js";
import { Msg } from "./Actions.js";
import { toArray } from "../fable_modules/fable-library.3.6.2/Option.js";
import { DateParsing_parse } from "../fable_modules/Feliz.1.57.0/Interop.fs.js";
import { ofArray } from "../fable_modules/fable-library.3.6.2/List.js";
export function DatePicker(datePickerInputProps) {
let value_2;
const updateDate = datePickerInputProps.updateDate;
const currentDate = datePickerInputProps.currentDate;
return createElement("input", createObj(ofArray([["type", "date"], (value_2 = currentDate, ["value", toString(value_2, "yyyy-MM-dd")]), ["onChange", (ev) => {
iterate((newValue) => {
updateDate(new Msg(0, newValue));
}, toArray(DateParsing_parse(ev.target.value)));
}]])));
}

12
dist/tests/src/Extensions.js vendored Normal file
View file

@ -0,0 +1,12 @@
import { isNullOrWhiteSpace } from "../fable_modules/fable-library.3.6.2/String.js";
export function Config_variableOrDefault(key, defaultValue) {
const foundValue = process.env[key] ? process.env[key] : '';
if (isNullOrWhiteSpace(foundValue)) {
return defaultValue;
}
else {
return foundValue;
}
}

6
dist/tests/src/Main.js vendored Normal file
View file

@ -0,0 +1,6 @@
import { render } from "react-dom";
import { createElement } from "react";
import { Container } from "./Container.js";
render(createElement(Container, null), document.getElementById("feliz-app"));

81
dist/tests/src/UserEntry.js vendored Normal file
View file

@ -0,0 +1,81 @@
import { Record, Union } from "../fable_modules/fable-library.3.6.2/Types.js";
import { list_type, record_type, union_type, string_type } from "../fable_modules/fable-library.3.6.2/Reflection.js";
import { empty, tryFind } from "../fable_modules/fable-library.3.6.2/List.js";
import { useReact_useEffect_3A5B6456, useFeliz_React__React_useState_Static_1505 } from "../fable_modules/Feliz.1.57.0/React.fs.js";
import { join, toConsole } from "../fable_modules/fable-library.3.6.2/String.js";
import { fetch$ } from "../fable_modules/Fable.Fetch.2.4.0/Fetch.fs.js";
import { format as format_1 } from "date-fns";
import { Auto_generateBoxedDecoder_79988AEF, fromString } from "../fable_modules/Thoth.Json.6.0.0/Decode.fs.js";
import { uncurry } from "../fable_modules/fable-library.3.6.2/Util.js";
import { CaseStrategy } from "../fable_modules/Thoth.Json.6.0.0/Types.fs.js";
import { createElement } from "react";
import { Interop_reactApi } from "../fable_modules/Feliz.1.57.0/Interop.fs.js";
export class State extends Union {
constructor(tag, ...fields) {
super();
this.tag = (tag | 0);
this.fields = fields;
}
cases() {
return ["LoadingScore", "ErrorFetchingScore", "LoadedScore", "NoScore"];
}
}
export function State$reflection() {
return union_type("UserEntry.State", [], State, () => [[], [], [["Item", string_type]], []]);
}
export class Score extends Record {
constructor(Name, Time) {
super();
this.Name = Name;
this.Time = Time;
}
}
export function Score$reflection() {
return record_type("UserEntry.Score", [], Score, () => [["Name", string_type], ["Time", string_type]]);
}
export function GetUserScore(scores, username) {
const _arg1 = tryFind((u) => (u.Name === username), scores);
if (_arg1 == null) {
return new State(3);
}
else {
return new State(2, _arg1.Time);
}
}
export function UserEntry(userEntryInputProps) {
const currentDate = userEntryInputProps.currentDate;
const username = userEntryInputProps.username;
const patternInput = useFeliz_React__React_useState_Static_1505(new State(0));
const setScore = patternInput[1];
const score = patternInput[0];
[useReact_useEffect_3A5B6456(() => {
let pr_1, pr;
toConsole(`Current Date == ${currentDate}`);
(pr_1 = ((pr = fetch$(`https://acicchetti.dev/crossword/v1/${format_1(currentDate, "yyyy-MM-dd")}`, empty()), pr.then((res) => res.text()))), pr_1.then((txt) => {
const decoded = fromString(uncurry(2, Auto_generateBoxedDecoder_79988AEF(list_type(Score$reflection()), new CaseStrategy(1), void 0)), txt);
if (decoded.tag === 1) {
setScore(new State(1));
}
else {
const apiResponse = decoded.fields[0];
toConsole(`got ${apiResponse}`);
setScore(GetUserScore(apiResponse, username));
}
}));
}), [currentDate]];
return createElement("div", {
className: join(" ", [(() => {
throw 1;
})()]),
children: Interop_reactApi.Children.toArray([createElement("div", {
children: `${username} - ${((score.tag === 1) ? "Error Fetching Score" : ((score.tag === 2) ? score.fields[0] : ((score.tag === 3) ? "No Score" : "Loading")))}`,
})]),
});
}

View file

@ -0,0 +1,5 @@
{
"version": 2,
"contentHash": "nM/hj3QIZxMP8fTIACpwSE4skIEW8zafTstiy8ZxDd7e3tOIgFU9vhy2//n+RNyDf/7T2FlFS8lb4YnZ3a+Ajw==",
"source": "https://api.nuget.org/v3/index.json"
}

Binary file not shown.

View file

@ -0,0 +1 @@
kpH/fx1hF7aVj0GIl0Q0wlVhB1RVqVgDBEn6yv7hkonFjzWULRa5pf4hEbDQbWVSiEHhB8SHLANrh8YpiPKshw==

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Femto</id>
<version>0.12.0</version>
<authors>Femto</authors>
<description>Package Description</description>
<releaseNotes>Add support for pnpm</releaseNotes>
<packageTypes>
<packageType name="DotnetTool" />
</packageTypes>
</metadata>
</package>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<DotNetCliTool Version="1">
<Commands>
<Command Name="femto" EntryPoint="Femto.dll" Runner="dotnet" />
</Commands>
</DotNetCliTool>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
{
"runtimeOptions": {
"tfm": "net5.0",
"rollForward": "Major",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "5.0.0"
}
}
}

View file

@ -0,0 +1,176 @@
{
"version": 3,
"targets": {
"net6.0": {
"Femto/0.12.0": {
"type": "package"
}
},
"net6.0/any": {
"Femto/0.12.0": {
"type": "package",
"tools": {
"tools/net5.0/any/Argu.dll": {},
"tools/net5.0/any/Dotnet.ProjInfo.Helpers.dll": {},
"tools/net5.0/any/Dotnet.ProjInfo.dll": {},
"tools/net5.0/any/DotnetToolSettings.xml": {},
"tools/net5.0/any/FSharp.Compiler.Service.dll": {},
"tools/net5.0/any/FSharp.Core.dll": {},
"tools/net5.0/any/Fable.Core.dll": {},
"tools/net5.0/any/Fake.Core.Context.dll": {},
"tools/net5.0/any/Fake.Core.Environment.dll": {},
"tools/net5.0/any/Fake.Core.FakeVar.dll": {},
"tools/net5.0/any/Fake.Core.Process.dll": {},
"tools/net5.0/any/Fake.Core.String.dll": {},
"tools/net5.0/any/Fake.Core.Trace.dll": {},
"tools/net5.0/any/Fake.IO.FileSystem.dll": {},
"tools/net5.0/any/Femto.deps.json": {},
"tools/net5.0/any/Femto.dll": {},
"tools/net5.0/any/Femto.pdb": {},
"tools/net5.0/any/Femto.runtimeconfig.json": {},
"tools/net5.0/any/Newtonsoft.Json.dll": {},
"tools/net5.0/any/SemVer.dll": {},
"tools/net5.0/any/Serilog.Sinks.Console.dll": {},
"tools/net5.0/any/Serilog.dll": {},
"tools/net5.0/any/System.Configuration.ConfigurationManager.dll": {},
"tools/net5.0/any/System.Security.Cryptography.ProtectedData.dll": {},
"tools/net5.0/any/Thoth.Json.Net.dll": {},
"tools/net5.0/any/cs/FSharp.Core.resources.dll": {},
"tools/net5.0/any/de/FSharp.Core.resources.dll": {},
"tools/net5.0/any/es/FSharp.Core.resources.dll": {},
"tools/net5.0/any/fr/FSharp.Core.resources.dll": {},
"tools/net5.0/any/it/FSharp.Core.resources.dll": {},
"tools/net5.0/any/ja/FSharp.Core.resources.dll": {},
"tools/net5.0/any/ko/FSharp.Core.resources.dll": {},
"tools/net5.0/any/pl/FSharp.Core.resources.dll": {},
"tools/net5.0/any/pt-BR/FSharp.Core.resources.dll": {},
"tools/net5.0/any/ru/FSharp.Core.resources.dll": {},
"tools/net5.0/any/runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll": {},
"tools/net5.0/any/tr/FSharp.Core.resources.dll": {},
"tools/net5.0/any/zh-Hans/FSharp.Core.resources.dll": {},
"tools/net5.0/any/zh-Hant/FSharp.Core.resources.dll": {}
}
}
}
},
"libraries": {
"Femto/0.12.0": {
"sha512": "nM/hj3QIZxMP8fTIACpwSE4skIEW8zafTstiy8ZxDd7e3tOIgFU9vhy2//n+RNyDf/7T2FlFS8lb4YnZ3a+Ajw==",
"type": "package",
"path": "femto/0.12.0",
"hasTools": true,
"files": [
".nupkg.metadata",
".signature.p7s",
"femto.0.12.0.nupkg.sha512",
"femto.nuspec",
"tools/net5.0/any/Argu.dll",
"tools/net5.0/any/Dotnet.ProjInfo.Helpers.dll",
"tools/net5.0/any/Dotnet.ProjInfo.dll",
"tools/net5.0/any/DotnetToolSettings.xml",
"tools/net5.0/any/FSharp.Compiler.Service.dll",
"tools/net5.0/any/FSharp.Core.dll",
"tools/net5.0/any/Fable.Core.dll",
"tools/net5.0/any/Fake.Core.Context.dll",
"tools/net5.0/any/Fake.Core.Environment.dll",
"tools/net5.0/any/Fake.Core.FakeVar.dll",
"tools/net5.0/any/Fake.Core.Process.dll",
"tools/net5.0/any/Fake.Core.String.dll",
"tools/net5.0/any/Fake.Core.Trace.dll",
"tools/net5.0/any/Fake.IO.FileSystem.dll",
"tools/net5.0/any/Femto.deps.json",
"tools/net5.0/any/Femto.dll",
"tools/net5.0/any/Femto.pdb",
"tools/net5.0/any/Femto.runtimeconfig.json",
"tools/net5.0/any/Newtonsoft.Json.dll",
"tools/net5.0/any/SemVer.dll",
"tools/net5.0/any/Serilog.Sinks.Console.dll",
"tools/net5.0/any/Serilog.dll",
"tools/net5.0/any/System.Configuration.ConfigurationManager.dll",
"tools/net5.0/any/System.Security.Cryptography.ProtectedData.dll",
"tools/net5.0/any/Thoth.Json.Net.dll",
"tools/net5.0/any/cs/FSharp.Core.resources.dll",
"tools/net5.0/any/de/FSharp.Core.resources.dll",
"tools/net5.0/any/es/FSharp.Core.resources.dll",
"tools/net5.0/any/fr/FSharp.Core.resources.dll",
"tools/net5.0/any/it/FSharp.Core.resources.dll",
"tools/net5.0/any/ja/FSharp.Core.resources.dll",
"tools/net5.0/any/ko/FSharp.Core.resources.dll",
"tools/net5.0/any/pl/FSharp.Core.resources.dll",
"tools/net5.0/any/pt-BR/FSharp.Core.resources.dll",
"tools/net5.0/any/ru/FSharp.Core.resources.dll",
"tools/net5.0/any/runtimes/win/lib/netstandard2.0/System.Security.Cryptography.ProtectedData.dll",
"tools/net5.0/any/tr/FSharp.Core.resources.dll",
"tools/net5.0/any/zh-Hans/FSharp.Core.resources.dll",
"tools/net5.0/any/zh-Hant/FSharp.Core.resources.dll"
]
}
},
"projectFileDependencyGroups": {
"net6.0": [
"femto >= *"
]
},
"packageFolders": {
"/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "/var/folders/jr/rvssj8b10x99t1pjt6zjs9bm0000gn/T/n3wfnwt2.xtt/restore.csproj",
"projectName": "restore",
"projectPath": "/var/folders/jr/rvssj8b10x99t1pjt6zjs9bm0000gn/T/n3wfnwt2.xtt/restore.csproj",
"packagesPath": "/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2",
"outputPath": "/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2/",
"projectStyle": "DotnetToolReference",
"configFilePaths": [
"/Users/acicchetti/src/Crossword-Fable/NuGet.Config",
"/Users/acicchetti/.nuget/NuGet/NuGet.Config"
],
"originalTargetFrameworks": [
"net6.0"
],
"sources": {
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
}
},
"frameworks": {
"net6.0": {
"targetAlias": "net6.0",
"dependencies": {
"femto": {
"target": "Package",
"version": "[*, )"
}
},
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48"
],
"assetTargetFallback": true,
"warn": true,
"runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/6.0.101/RuntimeIdentifierGraph.json"
}
},
"runtimes": {
"any": {
"#import": []
}
}
}
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">DotnetToolReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">6.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2/" />
</ItemGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgFemto Condition=" '$(PkgFemto)' == '' ">/Users/acicchetti/src/Crossword-Fable/femto/.store/.stage/cul4qrpd.hl2/femto/0.12.0</PkgFemto>
</PropertyGroup>
</Project>

BIN
femto/femto Executable file

Binary file not shown.

17241
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,45 +2,48 @@
"private": true,
"scripts": {
"prestart": "dotnet tool restore",
"start": "dotnet fable watch ./src -s --run webpack-dev-server",
"start": "dotnet fable watch src/App.fsproj --sourceMaps --run webpack serve",
"build": "dotnet fable src/App.fsproj --run webpack --node-env production",
"css": "tailwind build -i content/tailwind-source.css -o content/tailwind-generated.css",
"browsers": "browserslist --update-db",
"prebuild": "dotnet tool restore",
"build": "dotnet fable ./src && webpack",
"test:live": "dotnet fable watch tests --run webpack-dev-server --config ./webpack.tests.js",
"build:test": "dotnet fable tests && webpack --config webpack.tests.js",
"pretest": "dotnet tool restore",
"test": "dotnet fable tests --outDir dist/tests && mocha dist/tests -r esm"
},
"browserslist": [
"> 0.25%",
"not dead"
],
"dependencies": {
"date-fns": "^2.16.1",
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"@babel/core": "^7.16.5",
"@babel/preset-env": "^7.16.5",
"@babel/preset-react": "^7.16.5",
"@babel/runtime": "^7.12.5",
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
"babel-loader": "^8.2.2",
"copy-webpack-plugin": "^6.4.1",
"core-js": "^3.8.2",
"css-loader": "^5.0.1",
"dotenv-webpack": "^6.0.0",
"esm": "^3.2.25",
"file-loader": "^6.2.0",
"graceful-fs": "^4.2.4",
"html-webpack-plugin": "^4.5.1",
"mini-css-extract-plugin": "^1.3.4",
"mocha": "^8.2.1",
"react-refresh": "^0.9.0",
"sass": "^1.32.4",
"sass-loader": "^10.1.1",
"source-map-loader": "^2.0.1",
"style-loader": "^2.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"autoprefixer": "^10.4.0",
"babel-loader": "^8.2.3",
"browserslist": "^4.19.1",
"copy-webpack-plugin": "^10.2.0",
"core-js": "^3.20.0",
"css-loader": "^6.5.1",
"cssnano": "^5.0.14",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.4.5",
"postcss": "^8.4.5",
"postcss-loader": "^6.2.1",
"react-refresh": "^0.11.0",
"source-map-loader": "^3.0.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.0.7",
"terser": "^4.8.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.7.1"
}
}

15
postcss.config.js Normal file
View file

@ -0,0 +1,15 @@
const isDevelopment = process.env.WEBPACK_SERVE === 'true';
const cssnano = require('cssnano')({
preset: ['default', {
discardComments: { removeAll: true }
}]
})
module.exports = {
plugins: [
require('tailwindcss')
, require('autoprefixer')
, !isDevelopment && cssnano
].filter(Boolean)
};

View file

@ -3,7 +3,6 @@
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Include="index.html" />
<Compile Include="Extensions.fs" />
<Compile Include="Actions.fs" />
<Compile Include="DatePicker.fs" />

View file

@ -1,11 +1,7 @@
module Main
open System
open Feliz
open App
open Browser.Dom
open Fable.Core.JsInterop
importSideEffects "./styles/global.scss"
ReactDOM.render (Container.Container(), document.getElementById "feliz-app")

View file

@ -6,6 +6,20 @@ open Fable.DateFunctions
open Fetch
open Thoth.Json
open Zanaptak.TypedCssClasses
// Configure type provider to use generated Tailwind classes.
// Naming.Verbatim is required for PurgeCSS bundle reduction, see https://tailwindcss.com/docs/optimizing-for-production
type tw =
CssClasses<
source = "./content/tailwind-source.css"
, naming = Naming.Verbatim
, commandFile = "node"
, argumentPrefix = "./tailwind-process.js ./tailwind.config.js"
, resolutionFolder = "."
//, logFile = "TypedCssClasses.log" // uncomment to enable logging
>
type State =
| LoadingScore
| ErrorFetchingScore
@ -28,26 +42,6 @@ let UserEntry (username: string, currentDate: DateTime) =
let (score, setScore) = React.useState (LoadingScore)
let load () =
async {
printfn $"Current Date == {currentDate}"
fetch $"""https://acicchetti.dev/crossword/v1/{currentDate.Format "YYYY-MM-DD"}""" []
|> Promise.bind (fun res -> res.text ())
|> Promise.map
(fun txt ->
let decoded =
Decode.Auto.fromString<ScoreApiResponse> (txt, caseStrategy = CamelCase)
match decoded with
| Ok (apiResponse) ->
printfn $"""got {apiResponse}"""
let score = GetUserScore apiResponse username
setScore (score)
| Error (_) -> setScore (ErrorFetchingScore))
|> ignore
}
React.useEffect
(fun () ->
printfn $"Current Date == {currentDate}"
@ -68,10 +62,10 @@ let UserEntry (username: string, currentDate: DateTime) =
|> ignore),
[| box currentDate |]
Html.article [ props.className
Html.h1 [ prop.text
Html.div [ prop.classes [tw.``mx-auto``]
prop.children [ Html.div [ prop.text
$"""{username} - {match score with
| LoadingScore -> "Loading"
| ErrorFetchingScore -> "Error Fetching Score"
| LoadedScore s -> s
| NoScore -> "No Score"}""" ] ]
| NoScore -> "No Score"}""" ] ] ]

View file

@ -1,16 +0,0 @@
<!doctype html>
<html>
<head>
<title>Feliz App</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/png" href="img/favicon-32x32.png"
sizes="32x32"/>
<link rel="shortcut icon" type="image/png" href="img/favicon-16x16.png"
sizes="16x16"/>
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=es6"></script>
</head>
<body>
<div id="feliz-app"></div>
</body>
</html>

View file

3
src/styles/input.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

26
tailwind-process.js Normal file
View file

@ -0,0 +1,26 @@
const fs = require('fs')
const tailwindConfigFile = fs.realpathSync(process.argv[2])
const inputFile = fs.realpathSync(process.argv[3])
const postcss = require('postcss')
const tailwindcss = require('tailwindcss')(tailwindConfigFile)
const css = fs.readFileSync(inputFile)
postcss()
.use(tailwindcss)
.process(css, { from: inputFile })
.then(result => {
// write included files as leading output lines
result.messages
.filter(msg => msg.type === "dependency" && msg.file !== inputFile)
.forEach(msg => console.log(msg.file))
// write the final CSS output
console.log("/* ---- end included files, begin generated CSS ---- */")
console.log(result.css)
})
.catch(reason => {
console.error(reason)
process.exit(1)
})

10
tailwind.config.js Normal file
View file

@ -0,0 +1,10 @@
module.exports = {
content: [
"./src/**/*.js",
'./content/**/*.html',
],
theme: {
extend: {},
},
plugins: [],
}

View file

@ -1,163 +1,90 @@
// Template for webpack.config.js in Fable projects
// In most cases, you'll only need to edit the CONFIG object (after dependencies)
// See below if you need better fine-tuning of Webpack options
var path = require("path");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const {patchGracefulFileSystem} = require("./webpack.common.js");
patchGracefulFileSystem();
const path = require('path');
// If we're running the webpack-dev-server, assume we're in development mode
var isProduction = !process.argv.find(v => v.indexOf('webpack-dev-server') !== -1);
const HtmlWebpackPlugin = require('html-webpack-plugin'); // Inject <script> or <link> tags for generated bundles into index.html template
const CopyWebpackPlugin = require('copy-webpack-plugin'); // Copy static assets to output directory
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // Extract CSS from bundle to a different file
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin'); // Enable React Fast Refresh
const isDevelopment = !isProduction && process.env.NODE_ENV !== 'production';
// Development mode if running 'webpack serve'
const isDevelopment = process.env.WEBPACK_SERVE === 'true'
console.log('Bundling for ' + (isDevelopment ? 'development' : 'production') + '...');
var CONFIG = {
// The tags to include the generated JS and CSS will be automatically injected in the HTML template
// See https://github.com/jantimon/html-webpack-plugin
indexHtmlTemplate: "./src/index.html",
fsharpEntry: "./src/Main.fs.js",
outputDir: "./dist",
assetsDir: "./public",
devServerPort: 8080,
// When using webpack-dev-server, you may need to redirect some calls
// to a external API server. See https://webpack.js.org/configuration/dev-server/#devserver-proxy
devServerProxy: {
'/api/*': {
// assuming the backend is running on port 5000
target: "http://localhost:5000",
changeOrigin: true
}
},
// Use babel-preset-env to generate JS compatible with most-used browsers.
// More info at https://babeljs.io/docs/en/next/babel-preset-env.html
babel: {
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean),
presets: ["@babel/preset-env", "@babel/preset-react"]
}
}
console.log("Bundling for " + (isProduction ? "production" : "development") + "...");
// The HtmlWebpackPlugin allows us to use a template for the index.html page
// and automatically injects <script> or <link> tags for generated bundles.
var commonPlugins = [
new HtmlWebpackPlugin({
filename: 'index.html',
template: resolve(CONFIG.indexHtmlTemplate)
}),
new Dotenv({
path: "./.env",
silent: false,
systemvars: true
})
];
// Note: Tailwind performs CSS purging based on NODE_ENV environment variable, not webpack mode,
// so production builds should be launched with 'webpack --node-env production'
module.exports = {
// In development, bundle styles together with the code so they can also
// trigger hot reloads. In production, put them in a separate CSS file.
mode: isDevelopment ? 'development' : 'production',
entry: {
app: [resolve(CONFIG.fsharpEntry)]
app: ['./src/Main.fs.js', './content/tailwind-source.css']
},
// Add a hash to the output file name in production
// to prevent browser caching if code changes
// Add a hash to the output file name in production to prevent browser caching if code changes
output: {
path: resolve(CONFIG.outputDir),
filename: isProduction ? '[name].[hash].js' : '[name].js'
filename: isDevelopment ? '[name].js' : '[name].[contenthash].js',
},
mode: isProduction ? "production" : "development",
devtool: isProduction ? "source-map" : "eval-source-map",
optimization: {
// Split the code coming from npm packages into a different file.
// 3rd party dependencies change less often, let the browser cache them.
splitChunks: {
cacheGroups: {
commons: {
test: /node_modules/,
name: "vendors",
chunks: "all"
}
}
},
},
// Besides the HtmlPlugin, we use the following plugins:
// PRODUCTION
// - MiniCssExtractPlugin: Extracts CSS from bundle to a different file
// To minify CSS, see https://github.com/webpack-contrib/mini-css-extract-plugin#minimizing-for-production
// - CopyWebpackPlugin: Copies static assets to output directory
// DEVELOPMENT
// - HotModuleReplacementPlugin: Enables hot reloading when code changes without refreshing
plugins: isProduction ?
commonPlugins.concat([
new MiniCssExtractPlugin({filename: 'style.[contenthash].css'}),
new CopyWebpackPlugin({
patterns: [
{from: resolve(CONFIG.assetsDir)}
]
// Enable source maps in development mode
...(isDevelopment && { devtool: 'eval-source-map' }),
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './content/index.html'
}),
])
: commonPlugins.concat([
new ReactRefreshWebpackPlugin()
]),
resolve: {
// See https://github.com/fable-compiler/Fable/issues/1490
symlinks: false,
modules: [resolve("./node_modules")],
alias: {
// Some old libraries still use an old specific version of core-js
// Redirect the imports of these libraries to the newer core-js
'core-js/es6': 'core-js/es'
!isDevelopment && new CopyWebpackPlugin({ patterns: [{ from: './content/assets' }] }),
!isDevelopment && new MiniCssExtractPlugin({ filename: 'style.[contenthash].css' }),
isDevelopment && new ReactRefreshWebpackPlugin(),
].filter(Boolean),
devServer: {
static: {
directory: path.resolve(__dirname, './content/assets'),
}
},
// Configuration for webpack-dev-server
devServer: {
publicPath: "/",
contentBase: resolve(CONFIG.assetsDir),
port: CONFIG.devServerPort,
proxy: CONFIG.devServerProxy,
hot: true,
inline: true
},
// - babel-loader: transforms JS to old syntax (compatible with old browsers)
// - sass-loaders: transforms SASS/SCSS into JS
// - file-loader: Moves files referenced in the code (fonts, images) into output folder
module: {
rules: [
{
test: /\.(js|jsx)$/,
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: CONFIG.babel
},
},
options: {
presets: [
[
// Use babel-preset-env to generate JS compatible with most-used browsers.
// More info at https://babeljs.io/docs/en/babel-preset-env.html
'@babel/preset-env',
{
test: /\.(sass|scss|css)$/,
use: [
isProduction
? MiniCssExtractPlugin.loader
: 'style-loader',
{
loader: 'css-loader',
},
{
loader: 'sass-loader',
options: {implementation: require("sass")}
// This adds polyfills when needed. Requires core-js dependency.
// See https://babeljs.io/docs/en/babel-preset-env#usebuiltins
// Note that you still need to add custom polyfills if necessary (e.g. whatwg-fetch)
useBuiltIns: 'usage',
corejs: '3.15',
}
],
'@babel/preset-react'
],
plugins: [
isDevelopment && require.resolve('react-refresh/babel'),
].filter(Boolean),
}
}
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?.*)?$/,
use: ["file-loader"]
}
test: /\.css$/,
use: [
isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
].filter(Boolean),
},
]
}
};
function resolve(filePath) {
return path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
}