Browse Source

Initial commit

master
Sven Slootweg 2 months ago
commit
3f67beaaa6
  1. 3
      .eslintrc
  2. 2
      .gitignore
  3. 43
      bin/server.js
  4. 11
      knexfile.js
  5. 3
      notes.txt
  6. 46
      package.json
  7. 11
      postcss.config.js
  8. 62
      public/css/style.css
  9. 113
      public/images/logo.svg
  10. 47
      src/app.js
  11. 65
      src/css/style.css
  12. 70
      src/frontend/components/datasheet-search.css
  13. 125
      src/frontend/components/datasheet-search.jsx
  14. 8
      src/frontend/index.jsx
  15. 42
      src/views/index.jsx
  16. 6565
      yarn.lock

3
.eslintrc

@ -0,0 +1,3 @@
{
"extends": "@joepie91/eslint-config/react"
}

2
.gitignore

@ -0,0 +1,2 @@
node_modules
config.json

43
bin/server.js

@ -0,0 +1,43 @@
"use strict";
const Promise = require("bluebird");
const budoExpress = require("budo-express");
const path = require("path");
return Promise.try(() => {
return require("../src/app");
}).then((app) => {
budoExpress({
// port: 3000,
// port: 3100,
port: 3500,
allowUnsafeHost: true,
expressApp: app,
basePath: path.join(__dirname, ".."),
entryFiles: "src/frontend/index.jsx",
staticPath: "public",
bundlePath: "js/bundle.js",
livereloadPattern: "**/*.{css,html,js}",
browserify: {
extensions: [".jsx"],
plugin: [
[ "icssify", {
before: [
// require('postcss-import')(),
require('postcss-mixins')(),
require("postcss-nested")(),
require('postcss-simple-vars')(),
require('postcss-color-function')(),
require('autoprefixer')()
]
}] // FIXME: css-extract
],
transform: [
["babelify", {
presets: ["@babel/preset-env", "@babel/preset-react"],
}],
]
}
});
});

11
knexfile.js

@ -0,0 +1,11 @@
"use strict";
const config = require("./config.json");
module.exports = {
client: "pg",
connection: {
host: config.database.socketPath,
database: config.database.database
}
};

3
notes.txt

@ -0,0 +1,3 @@
Note: text_pattern_ops index is needed for prefix LIKE to be guaranteed-fast
CREATE INDEX search_index ON items ((lower(data ->> 'name'::text)) text_pattern_ops);

46
package.json

@ -0,0 +1,46 @@
{
"name": "ui",
"version": "1.0.0",
"main": "index.js",
"repository": "git@git.cryto.net:seekseek/ui.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"scripts": {
"dev": "NODE_ENV=development nodemon --ext js,jsx,mjs,json,ftl --ignore node_modules --ignore public/js --ignore src/frontend bin/server.js",
"dev-css": "postcss --watch src/css/style.css -o public/css/style.css"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.12.7",
"@joepie91/eslint-config": "^1.1.0",
"autoprefixer": "^9.0.0",
"babelify": "^10.0.0",
"budo-express": "^1.0.6",
"eslint": "^7.15.0",
"eslint-plugin-react": "^7.21.5",
"eslint-plugin-react-hooks": "^4.2.0",
"icssify": "^1.2.1",
"nodemon": "^2.0.6",
"postcss": "^8.2.1",
"postcss-cli": "^8.3.1",
"postcss-color-function": "^4.1.0",
"postcss-mixins": "^6",
"postcss-nested": "^4",
"postcss-simple-vars": "^5"
},
"dependencies": {
"@joepie91/express-react-views": "^1.0.1",
"axios": "^0.21.1",
"bluebird": "^3.7.2",
"classnames": "^2.2.6",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"knex": "^0.95.2",
"match-value": "^1.1.0",
"pg": "^8.5.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"syncpipe": "^1.0.0"
}
}

11
postcss.config.js

@ -0,0 +1,11 @@
"use strict";
module.exports = {
plugins: [
require('postcss-mixins')(),
require("postcss-nested")(),
require('postcss-simple-vars')(),
require('postcss-color-function')(),
require('autoprefixer')()
]
};

62
public/css/style.css

@ -0,0 +1,62 @@
html, body {
/* background-color: rgb(248, 249, 236); */
background-color: #f9f9f9ff;
font-family: sans-serif;
margin: 0;
padding: 0;
}
.wrapper {
max-width: 900px;
margin-left: 1em;
margin-right: 1em;
}
.header {
margin-top: 1em;
margin-left: 0.5em;
margin-right: 0.5em;
padding-bottom: .7em;
border-bottom: 2px solid black;
}
.contents {
margin-bottom: 2em;
padding: .7em 0;
}
.footer {
position: fixed;
bottom: 0;
left: 0.5em;
right: 0.5em;
box-sizing: border-box;
border-top: 1px solid black;
height: 2em;
padding: 0.2em;
background-color: #f9f9f9ff;
}
.footer .wrapper {
margin-left: calc(1em - 0.5em);
}
.logoContainer {
display: inline-block;
position: relative;
}
.logoContainer .logo {
height: 5em;
}
.logoContainer .siteTag {
position: absolute;
right: 0;
bottom: 0;
color: teal;
font-size: 1.3em;
}

113
public/images/logo.svg

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="624.12909"
height="149.9104"
viewBox="0 0 165.13416 39.663792"
version="1.1"
id="svg851"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
sodipodi:docname="logo.svg"
inkscape:export-filename="/home/sven/magnifier.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs845" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="290.07278"
inkscape:cy="-52.014372"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1051"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata848">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-137.20652,-103.9911)">
<g
aria-label="seekseek"
id="text905"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;line-height:36.6346px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1">
<path
d="m 197.21016,126.62008 q 0,2.1082 -1.4986,3.2512 -1.4732,1.1176 -4.4196,1.1176 -1.4478,0 -2.4892,-0.2032 -1.0414,-0.1778 -2.0828,-0.6096 v -3.1242 q 1.1176,0.508 2.413,0.8382 1.2954,0.3302 2.286,0.3302 1.1176,0 1.5748,-0.3302 0.4826,-0.3302 0.4826,-0.8636 0,-0.3556 -0.2032,-0.635 -0.1778,-0.2794 -0.8128,-0.635 -0.635,-0.3556 -1.9812,-0.9144 -1.2954,-0.5588 -2.1336,-1.0922 -0.8382,-0.5588 -1.2446,-1.3208 -0.4064,-0.7874 -0.4064,-1.9558 0,-1.9304 1.4986,-2.8956 1.4986,-0.9652 3.9878,-0.9652 1.2954,0 2.4638,0.254 1.1684,0.254 2.413,0.8382 l -1.143,2.7178 q -1.016,-0.4318 -1.9304,-0.7112 -0.9144,-0.3048 -1.8542,-0.3048 -1.6764,0 -1.6764,0.9144 0,0.3302 0.2032,0.6096 0.2286,0.254 0.8382,0.5588 0.635,0.3048 1.8542,0.8128 1.1938,0.4826 2.0574,1.016 0.8636,0.508 1.3208,1.2954 0.4826,0.762 0.4826,2.0066 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1512" />
<path
d="m 205.87155,116.61248 q 2.8702,0 4.5466,1.651 1.6764,1.6256 1.6764,4.6482 v 1.8288 h -8.9408 q 0.0508,1.6002 0.9398,2.5146 0.9144,0.9144 2.5146,0.9144 1.3462,0 2.4384,-0.254 1.0922,-0.2794 2.2606,-0.8382 v 2.921 q -1.016,0.508 -2.159,0.7366 -1.1176,0.254 -2.7178,0.254 -2.0828,0 -3.683,-0.762 -1.6002,-0.7874 -2.5146,-2.3622 -0.9144,-1.5748 -0.9144,-3.9624 0,-2.4384 0.8128,-4.0386 0.8382,-1.6256 2.3114,-2.4384 1.4732,-0.8128 3.429,-0.8128 z m 0.0254,2.6924 q -1.0922,0 -1.8288,0.7112 -0.7112,0.7112 -0.8382,2.2098 h 5.3086 q -0.0254,-1.27 -0.6604,-2.0828 -0.635,-0.8382 -1.9812,-0.8382 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1514" />
<path
d="m 220.88294,116.61248 q 2.8702,0 4.5466,1.651 1.6764,1.6256 1.6764,4.6482 v 1.8288 h -8.9408 q 0.0508,1.6002 0.9398,2.5146 0.9144,0.9144 2.5146,0.9144 1.3462,0 2.4384,-0.254 1.0922,-0.2794 2.2606,-0.8382 v 2.921 q -1.016,0.508 -2.159,0.7366 -1.1176,0.254 -2.7178,0.254 -2.0828,0 -3.683,-0.762 -1.6002,-0.7874 -2.5146,-2.3622 -0.9144,-1.5748 -0.9144,-3.9624 0,-2.4384 0.8128,-4.0386 0.8382,-1.6256 2.3114,-2.4384 1.4732,-0.8128 3.429,-0.8128 z m 0.0254,2.6924 q -1.0922,0 -1.8288,0.7112 -0.7112,0.7112 -0.8382,2.2098 h 5.3086 q -0.0254,-1.27 -0.6604,-2.0828 -0.635,-0.8382 -1.9812,-0.8382 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1516" />
<path
d="m 233.96393,111.43088 v 8.636 q 0,0.7874 -0.0762,1.5748 -0.0508,0.762 -0.127,1.5494 h 0.0508 q 0.381,-0.5334 0.7874,-1.0668 0.4064,-0.5588 0.8636,-1.0414 l 3.8862,-4.2164 h 4.2672 l -5.5118,6.0198 5.842,7.8486 h -4.3688 l -3.9878,-5.6134 -1.6256,1.2954 v 4.318 h -3.7846 v -19.304 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1518" />
<path
d="m 255.60471,126.62008 q 0,2.1082 -1.4986,3.2512 -1.4732,1.1176 -4.4196,1.1176 -1.4478,0 -2.4892,-0.2032 -1.0414,-0.1778 -2.0828,-0.6096 v -3.1242 q 1.1176,0.508 2.413,0.8382 1.2954,0.3302 2.286,0.3302 1.1176,0 1.5748,-0.3302 0.4826,-0.3302 0.4826,-0.8636 0,-0.3556 -0.2032,-0.635 -0.1778,-0.2794 -0.8128,-0.635 -0.635,-0.3556 -1.9812,-0.9144 -1.2954,-0.5588 -2.1336,-1.0922 -0.8382,-0.5588 -1.2446,-1.3208 -0.4064,-0.7874 -0.4064,-1.9558 0,-1.9304 1.4986,-2.8956 1.4986,-0.9652 3.9878,-0.9652 1.2954,0 2.4638,0.254 1.1684,0.254 2.413,0.8382 l -1.143,2.7178 q -1.016,-0.4318 -1.9304,-0.7112 -0.9144,-0.3048 -1.8542,-0.3048 -1.6764,0 -1.6764,0.9144 0,0.3302 0.2032,0.6096 0.2286,0.254 0.8382,0.5588 0.635,0.3048 1.8542,0.8128 1.1938,0.4826 2.0574,1.016 0.8636,0.508 1.3208,1.2954 0.4826,0.762 0.4826,2.0066 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1520" />
<path
d="m 264.2661,116.61248 q 2.8702,0 4.5466,1.651 1.6764,1.6256 1.6764,4.6482 v 1.8288 h -8.9408 q 0.0508,1.6002 0.9398,2.5146 0.9144,0.9144 2.5146,0.9144 1.3462,0 2.4384,-0.254 1.0922,-0.2794 2.2606,-0.8382 v 2.921 q -1.016,0.508 -2.159,0.7366 -1.1176,0.254 -2.7178,0.254 -2.0828,0 -3.683,-0.762 -1.6002,-0.7874 -2.5146,-2.3622 -0.9144,-1.5748 -0.9144,-3.9624 0,-2.4384 0.8128,-4.0386 0.8382,-1.6256 2.3114,-2.4384 1.4732,-0.8128 3.429,-0.8128 z m 0.0254,2.6924 q -1.0922,0 -1.8288,0.7112 -0.7112,0.7112 -0.8382,2.2098 h 5.3086 q -0.0254,-1.27 -0.6604,-2.0828 -0.635,-0.8382 -1.9812,-0.8382 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1522" />
<path
d="m 279.27749,116.61248 q 2.8702,0 4.5466,1.651 1.6764,1.6256 1.6764,4.6482 v 1.8288 h -8.9408 q 0.0508,1.6002 0.9398,2.5146 0.9144,0.9144 2.5146,0.9144 1.3462,0 2.4384,-0.254 1.0922,-0.2794 2.2606,-0.8382 v 2.921 q -1.016,0.508 -2.159,0.7366 -1.1176,0.254 -2.7178,0.254 -2.0828,0 -3.683,-0.762 -1.6002,-0.7874 -2.5146,-2.3622 -0.9144,-1.5748 -0.9144,-3.9624 0,-2.4384 0.8128,-4.0386 0.8382,-1.6256 2.3114,-2.4384 1.4732,-0.8128 3.429,-0.8128 z m 0.0254,2.6924 q -1.0922,0 -1.8288,0.7112 -0.7112,0.7112 -0.8382,2.2098 h 5.3086 q -0.0254,-1.27 -0.6604,-2.0828 -0.635,-0.8382 -1.9812,-0.8382 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1524" />
<path
d="m 292.35848,111.43088 v 8.636 q 0,0.7874 -0.0762,1.5748 -0.0508,0.762 -0.127,1.5494 h 0.0508 q 0.381,-0.5334 0.7874,-1.0668 0.4064,-0.5588 0.8636,-1.0414 l 3.8862,-4.2164 h 4.2672 l -5.5118,6.0198 5.842,7.8486 h -4.3688 l -3.9878,-5.6134 -1.6256,1.2954 v 4.318 h -3.7846 v -19.304 z"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:25.4px;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';stroke-width:0.264583px"
id="path1526" />
</g>
<rect
style="opacity:0.99;fill:#333333;stroke-width:0.175183;paint-order:markers stroke fill"
id="rect1418"
width="5.357511"
height="22.925625"
x="195.92026"
y="-21.044689"
transform="rotate(45)" />
<path
id="path1414"
style="opacity:0.99;fill:#000000;stroke-width:0.175183;paint-order:markers stroke fill"
d="m 162.88237,103.99118 a 13.521487,13.521487 0 0 0 -9.51545,3.96032 13.521487,13.521487 0 0 0 0,19.12234 13.521487,13.521487 0 0 0 19.12235,0 13.521487,13.521487 0 0 0 0,-19.12234 13.521487,13.521487 0 0 0 -9.6069,-3.96032 z m 0.0151,4.51556 a 9.0058318,9.0058318 0 0 1 6.39856,2.6377 9.0058318,9.0058318 0 0 1 0,12.73615 9.0058318,9.0058318 0 0 1 -12.73616,0 9.0058318,9.0058318 0 0 1 0,-12.73615 9.0058318,9.0058318 0 0 1 6.3376,-2.6377 z" />
</g>
</svg>

47
src/app.js

@ -0,0 +1,47 @@
"use strict";
const Promise = require("bluebird");
const express = require("express");
const path = require("path");
const knex = require("knex")(require("../knexfile"));
let app = express();
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jsx");
app.engine("jsx", require("@joepie91/express-react-views").createEngine());
app.use(express.static(path.join(__dirname, "../public")));
app.get("/", (req, res) => {
res.redirect("/datasheets");
});
app.get("/datasheets", (req, res) => {
res.render("index");
});
app.post("/search", (req, res) => {
return Promise.try(() => {
return knex.raw(`
SELECT
data->>'manufacturer' AS manufacturer,
data->>'name' AS name,
data->>'url' AS url,
data->>'description' AS description,
data->>'source' AS source
FROM items WHERE
id LIKE 'datasheet:%'
AND lower(data->>'name') LIKE :query
ORDER BY name
LIMIT 20
`, {
query: req.query.query.toLowerCase() + "%"
});
}).then((result) => {
res.json({ results: result.rows });
});
});
module.exports = app;

65
src/css/style.css

@ -0,0 +1,65 @@
$pagePadding: 0.5em;
$background: #f9f9f9ff;
html, body {
/* background-color: rgb(248, 249, 236); */
background-color: $background;
font-family: sans-serif;
margin: 0;
padding: 0;
}
.wrapper {
max-width: 900px;
margin-left: 1em;
margin-right: 1em;
}
.header {
margin-top: 1em;
margin-left: $pagePadding;
margin-right: $pagePadding;
padding-bottom: .7em;
border-bottom: 2px solid black;
}
.contents {
margin-bottom: 2em;
padding: .7em 0;
}
.footer {
position: fixed;
bottom: 0;
left: $pagePadding;
right: $pagePadding;
box-sizing: border-box;
border-top: 1px solid black;
height: 2em;
padding: 0.2em;
background-color: $background;
.wrapper {
margin-left: calc(1em - $pagePadding);
}
}
.logoContainer {
display: inline-block;
position: relative;
.logo {
height: 5em;
}
.siteTag {
position: absolute;
right: 0;
bottom: 0;
color: teal;
font-size: 1.3em;
}
}

70
src/frontend/components/datasheet-search.css

@ -0,0 +1,70 @@
.query {
font-size: 1.3em;
background-color: white;
color: black;
border: 1px solid teal;
border-radius: 5px;
padding: .4em .8em;
width: 100%;
box-sizing: border-box;
}
.noResults {
padding: .6em 1em;
}
.results {
border: 1px solid teal;
border-radius: 5px;
/* margin-top: 1em; */
.result {
border-top: 1px solid teal;
padding: .6em 1em;
font-size: .8em;
&.first {
border-top: 0;
font-size: 1em
}
.name {
font-size: 1.3em;
.manufacturer {
color: #4f4e4e;
margin-right: .3em;
}
.model {
font-weight: bold;
}
}
.description {
color: #4f4e4e;
margin-top: .2em;
}
.download {
float: right;
text-decoration: none;
border-radius: 3px;
padding: .3em .8em;
margin-top: -.3em;
margin-right: -.7em;
border: 1px solid #006262;
background-color: #039f9f;
color: white;
}
}
}
.sources {
color: gray;
font-size: 0.8em;
margin-top: 1em;
margin-bottom: .3em;
}

125
src/frontend/components/datasheet-search.jsx

@ -0,0 +1,125 @@
"use strict";
const React = require("react");
const classnames = require("classnames");
const axios = require("axios");
const syncpipe = require("syncpipe");
const matchValue = require("match-value");
const style = require("./datasheet-search.css");
function getSources(results) {
return syncpipe(results, [
(_) => _.map((result) => result.source),
// (_) => _.filter((source) => source != null),
(_) => _.map((source) => source != null ? source : "unknown"),
(_) => new Set(_),
(_) => Array.from(_),
(_) => _.map((source) => {
return matchValue(source, {
tme: "TME",
lcsc: "LCSC",
st: "STMicroelectronics",
unknown: "Unknown"
});
})
]);
}
function SearchResult({ isFirst, name, description, url, manufacturer }) {
// FIXME: Handle 'no datasheet available'
return (
<div className={classnames(style.result, { [style.first]: isFirst })}>
<a href={url} className={style.download} target="_blank">
Download datasheet
</a>
<div className={style.name}>
<span className={style.manufacturer}>
{manufacturer}
</span>
<span className={style.model}>
{name}
</span>
</div>
<div className={style.description}>
{description}
</div>
</div>
);
}
function NoResults() {
return (
<div className={style.noResults}>
No results.
</div>
);
}
module.exports = function DatasheetSearch({}) {
let [ query, setQuery ] = React.useState(""); // FIXME
let [ results, setResults ] = React.useState([]);
let [ sources, setSources ] = React.useState([]);
let cancellationToken = React.useRef();
function updateQuery(event) {
setQuery(event.target.value.trim());
}
React.useEffect(() => {
let cancelled = false;
cancellationToken.current = axios.CancelToken.source();
if (query.length > 0) {
axios.post("/search", {}, {
params: { query: query }
})
.then((response) => {
if (!cancelled) {
setResults(response.data.results);
setSources(getSources(response.data.results));
}
})
.catch((error) => {
if (!axios.isCancel()) {
throw error;
}
});
} else {
setResults([]);
}
return function () {
cancelled = true;
cancellationToken.current.cancel("Query input changed");
};
}, [ query ]);
return (
<div className="search">
<input type="text" className={style.query} placeholder="Start typing..." onChange={updateQuery} />
<div className={style.sources}>
{(results.length > 0)
? <>
<strong>Sources:</strong>
&nbsp;
{sources.join(", ")}
</>
: null
}
</div>
<div className={style.results}>
{(results.length > 0)
? results.map((result, i) => {
return <SearchResult
isFirst={(i === 0)}
{...result}
/>;
})
: <NoResults />
}
</div>
</div>
);
};

8
src/frontend/index.jsx

@ -0,0 +1,8 @@
"use strict";
const React = require("react");
const ReactDOM = require("react-dom");
const DatasheetSearch = require("./components/datasheet-search");
ReactDOM.render(<DatasheetSearch />, document.querySelector("#datasheetSearch"));

42
src/views/index.jsx

@ -0,0 +1,42 @@
"use strict";
const React = require("react");
module.exports = function Index() {
return (
<html lang="en">
<head>
<meta charSet="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>seekseek</title>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body>
<div className="header">
<div className="wrapper">
<div className="logoContainer">
<img src="/images/logo.svg" alt="seekseek logo" className="logo"/>
<div className="siteTag">datasheets</div>
</div>
</div>
</div>
<div className="contents">
<div className="wrapper">
<div id="datasheetSearch">
Loading, please wait...
</div>
</div>
</div>
<div className="footer">
<div className="wrapper">
<a href="https://matrix.to/#/#seekseek:pixie.town?via=pixie.town&via=matrix.org&via=librepush.net" className="chat">
Come chat with us!
</a>
</div>
</div>
<script src="/js/bundle.js"></script>
</body>
</html>
);
};

6565
yarn.lock
File diff suppressed because it is too large
View File

Loading…
Cancel
Save