diff --git a/.gitignore b/.gitignore index e69de29..2d2b47d 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +node_modules \ No newline at end of file diff --git a/client-websocket.js b/client-websocket.js new file mode 100644 index 0000000..d9e089d --- /dev/null +++ b/client-websocket.js @@ -0,0 +1,27 @@ +(() => { + const socketUrl = 'ws://192.168.1.138:9878'; + let socket = new WebSocket(socketUrl); + socket.addEventListener('close', () => { + const interAttemptTimeoutMilliseconds = 100; + const maxDisconnectedTimeMilliseconds = 3000; + const maxAttempts = Math.round( + maxDisconnectedTimeMilliseconds / interAttemptTimeoutMilliseconds, + ); + let attempts = 0; + const reloadIfCanConnect = () => { + attempts++; + if (attempts > maxAttempts) { + console.error('Could not reconnect to dev server.'); + return; + } + socket = new WebSocket(socketUrl); + socket.addEventListener('error', () => { + setTimeout(reloadIfCanConnect, interAttemptTimeoutMilliseconds); + }); + socket.addEventListener('open', () => { + location.reload(); + }); + }; + reloadIfCanConnect(); + }); +})(); \ No newline at end of file diff --git a/dev-server.js b/dev-server.js new file mode 100644 index 0000000..b25cbdf --- /dev/null +++ b/dev-server.js @@ -0,0 +1,78 @@ +/** @file site/dev-server.js */ +const http = require('http'); +const fs = require('fs'); +const path = require('path'); +const WebSocket = require('ws'); + +const HTTP_PORT = 9876; +const WEBSOCKET_PORT = 9878; +const CLIENT_WEBSOCKET_CODE = fs.readFileSync( + path.join(__dirname, 'client-websocket.js'), + 'utf8', +); + +// Websocket server (for allowing browser and dev server to have 2-way communication) +// We don't even need to do anything except create the instance! +const wss = new WebSocket.Server({ + port: WEBSOCKET_PORT, +}); +wss.on('connection', () => { + console.log('Client connected'); +}); + +/** + * @typedef {import('http').IncomingMessage} req + * @typedef {import('http').ServerResponse} res + */ + +/** Use classic server-logic to serve a static file (e.g. default to 'index.html' etc) + * @param {string} route + * @param {res} res + * @returns {boolean} Whether or not the page exists and was served + */ +function serveStaticPageIfExists(route, res) { + // We don't care about performance for a dev server, so sync functions are fine. + // If the route exists it's either the exact file we want or the path to a directory + // in which case we'd serve up the 'index.html' file. + if (fs.existsSync(route)) { + if (fs.statSync(route).isDirectory()) { + return serveStaticPageIfExists(path.join(route, 'index.html'), res); + } else if (fs.statSync(route).isFile()) { + res.writeHead(200); + /** @type {string|Buffer} */ + let file = fs.readFileSync(route); + if (route.endsWith('.html')) { + // Inject the client-side websocket code. + // This sounds fancier than it is; simply + // append the script to the end since + // browsers allow for tons of deviation + // from *technically correct* HTML. + file = `${file.toString()}\n\n`; + } + res.end(file); + return true; + } + } + return false; +} + +/** General request handler and router + * @param {req} req + * @param {res} res + */ +const requestHandler = function (req, res) { + const method = req.method.toLowerCase(); + if (method === 'get') { + // No need to ensure the route can't access other local files, + // since this is for development only. + const route = path.normalize(path.join(__dirname, req.url)); + if (serveStaticPageIfExists(route, res)) { + return; + } + } + res.writeHead(404); + res.end(); +}; + +const server = http.createServer(requestHandler); +server.listen(HTTP_PORT); \ No newline at end of file diff --git a/images/arrow-1.png b/images/arrow-1.png new file mode 100644 index 0000000..11e8bad Binary files /dev/null and b/images/arrow-1.png differ diff --git a/images/arrow-2.png b/images/arrow-2.png new file mode 100644 index 0000000..c3a6f83 Binary files /dev/null and b/images/arrow-2.png differ diff --git a/images/autobasket_1.png b/images/autobasket_1.png new file mode 100644 index 0000000..3f6861c Binary files /dev/null and b/images/autobasket_1.png differ diff --git a/images/autobasket_2.png b/images/autobasket_2.png new file mode 100644 index 0000000..de43a7f Binary files /dev/null and b/images/autobasket_2.png differ diff --git a/images/autobasket_3.png b/images/autobasket_3.png new file mode 100644 index 0000000..da203ab Binary files /dev/null and b/images/autobasket_3.png differ diff --git a/images/balance-icon.png b/images/balance-icon.png new file mode 100644 index 0000000..922f528 Binary files /dev/null and b/images/balance-icon.png differ diff --git a/images/broc_meal_plan.png b/images/broc_meal_plan.png new file mode 100644 index 0000000..4c38130 Binary files /dev/null and b/images/broc_meal_plan.png differ diff --git a/images/economy-icon.png b/images/economy-icon.png new file mode 100644 index 0000000..91dd2b1 Binary files /dev/null and b/images/economy-icon.png differ diff --git a/images/google_play.png b/images/google_play.png new file mode 100644 index 0000000..f119777 Binary files /dev/null and b/images/google_play.png differ diff --git a/images/happy-salad.png b/images/happy-salad.png new file mode 100644 index 0000000..c61db31 Binary files /dev/null and b/images/happy-salad.png differ diff --git a/images/laugh-icon.png b/images/laugh-icon.png new file mode 100644 index 0000000..1166543 Binary files /dev/null and b/images/laugh-icon.png differ diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000..51810d6 Binary files /dev/null and b/images/logo.png differ diff --git a/images/personalization-icon.png b/images/personalization-icon.png new file mode 100644 index 0000000..2897834 Binary files /dev/null and b/images/personalization-icon.png differ diff --git a/images/rustore.png b/images/rustore.png new file mode 100644 index 0000000..ffd5d13 Binary files /dev/null and b/images/rustore.png differ diff --git a/images/smile-icon.png b/images/smile-icon.png new file mode 100644 index 0000000..afb1cba Binary files /dev/null and b/images/smile-icon.png differ diff --git a/index.html b/index.html index 8da8f42..21a3ab0 100644 --- a/index.html +++ b/index.html @@ -6,8 +6,233 @@ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
ХватилоПерсональный помощник
по питанию: баланс,
энергия, порядок
в холодильнике -
для всей семьи
Google play
+
RuStore
+ Вы выбираете, сколько человек в семье, указываете, на сколько дней нужны
продукты — и приложение мгновенно собирает корзину с учётом порций.
+
На выходе — чёткий список покупок, разбитый по отделам магазина
+ Забудьте про мучительные вопросы «А хватит ли?», «А что купить ещё?»
+
+ Список всегда под рукой, можно вычёркивать по пути
+
+ Мы уже учли, что есть в магазине
+
+ Добавляете любимые рецепты и указываете
+ возможные замены для продуктов. Из готовых
+ рецептов собираете план на день/неделю, планом
+ можно делиться с другими пользователями!
+
Вы сами выбираете блюда
Замена без потери вкуса
Общий план — муж/ребёнок/соседка по комнате знают, что готовить, без ваших объяснений
+
+ Добавляете любимые рецепты и указываете
+ возможные замены для продуктов. Из готовых
+
Открываете сегодняшний
день в плане питания
+ Заменить ужин — пара кликов,
и рецепт встаёт в план
с новым списком покупок

+ Из списка продуктов можно
сформировать автокорзину
на недостающие
