{"id":18304644,"url":"https://github.com/numtel/beach-report-lite","last_synced_at":"2025-04-09T10:37:19.155Z","repository":{"id":150130630,"uuid":"194153456","full_name":"numtel/beach-report-lite","owner":"numtel","description":"Lightweight version of beachreportcard.org","archived":false,"fork":false,"pushed_at":"2019-11-03T12:32:39.000Z","size":125,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-15T04:42:48.753Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://beach-report-lite.herokuapp.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/numtel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-27T19:40:52.000Z","updated_at":"2022-11-11T00:50:31.000Z","dependencies_parsed_at":"2023-04-18T05:17:34.854Z","dependency_job_id":null,"html_url":"https://github.com/numtel/beach-report-lite","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numtel%2Fbeach-report-lite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numtel%2Fbeach-report-lite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numtel%2Fbeach-report-lite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/numtel%2Fbeach-report-lite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/numtel","download_url":"https://codeload.github.com/numtel/beach-report-lite/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248021489,"owners_count":21034683,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T15:29:48.993Z","updated_at":"2025-04-09T10:37:19.123Z","avatar_url":"https://github.com/numtel.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Beach Report Lite [![Build Status](https://travis-ci.org/numtel/beach-report-lite.svg?branch=master)](https://travis-ci.org/numtel/beach-report-lite)\n\n* Example Node.js Application without 3rd-party dependencies\n* Lightweight version of [beachreportcard.org](https://beachreportcard.org)\n* Demo site [hosted on Heroku](https://beach-report-lite.herokuapp.com/)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://beach-report-lite.herokuapp.com/\"\u003e\n    \u003cimg src=\"docs/index.png\" alt=\"Index page screenshot\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Installation\n\n```sh\n$ git clone https://github.com/numtel/beach-report-lite.git\n$ cd beach-report-lite\n\n# \"npm install\" not required since there's no dependencies!\n\n# Serve on port 3000\n$ npm start\n\n# Run test suite\n$ npm test\n```\n\n### Configuration\n\nEnvironment Variable | Default | Description\n---------------------|---------|------------------\n`PORT`               | `3000`  | Listen for HTTP connections on this port\n`ENFORCE_HTTPS`      | `false` | Redirect 302 to HTTPS based on `x-forwarded-proto` header\n`REFRESH_INTERVAL`   | `3*60*60*1000` | Cache API data for specified duration (default 3 hours)\n\n## Design Philosophy\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://twitter.com/jaredpalmer/status/1142800704580591617\"\u003e\n    \u003cimg src=\"docs/stack.jpg\" alt=\"Multi-stacked rafts\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nTweeted as [\"Modern Web Development\"](https://twitter.com/jaredpalmer/status/1142800704580591617), many web developers have felt like this adventurous captain piloting a stack of rafts through white water.\n\nThings were so simple when writing PHP. Upload some `.php` files to a shared hosting account then browse. Persistant data between requests would take another application, like Redis or Memcache, on the stack though.\n\nI wonder, what does it take to write a dynamic website using Node.js without any dependencies?\n\nMany websites built today link with a vast web of modules in order to make the developer's experience as high-level as possible. Writing succinct, easy-to-debug code without relying on a tall stack of packages is still possible.\n\nThis is not a prescription that all applications should be written this way, but to serve as a spark for the imagination.\n\n### Back-end\n\n#### No left-pad surpises\n\nJavascript, and by extention Node.js, have frequently been criticised for their lack of standard library.\n\nIn this project, regularly-used packages such as Express, EJS, Request, and Nodeunit have been replaced with custom classes and functions that only require built-in Node.js modules.\n\n### Front-end\n\nThe dream of the 90s is alive in simple, accessible pages.\n\n#### Element Attribute Event Handlers not considered evil\n\nShunned since Y2K, using event handlers in HTML element attributes is widely considered bad practice. Rethink this and see that they might actually be the best practice. In the search form, they are used in order to connect the form inputs to eachother for easier input.\n\n```html\n\u003cselect id=\"lat_sel\"\n    onclick=\"event.target.form.lat.value = event.target.value\"\n    onchange=\"event.target.form.lat.value = event.target.value\"\u003e\n```\n\nIn the case of this select element, both the `onclick` and `onchange` handlers must be defined in order to handle how various browsers interpret selecting a new value but in accordance with KISS pricipals, abstracting this short statement into a function would be more trouble than it's worth. Form input elements with the `id` attribute specified may be accessed under the form object by their id, no extra code to manage fields required.\n\nModern Javascript view libraries like React, Vue, and LitHtml all provide custom implementations of these attribute event handlers. The standard ones work fine though and an extra library is not required.\n\n```html\n\u003cbutton type=\"button\" onclick=\"setLatToMe(event.target.form)\"\u003eUse my location\u003c/button\u003e\n```\n\nIn the case of the \"Use my location\" button, the method is a bit too verbose to fit into the attribute value so a separate function is defined and invoked. This function exists in the global scope because when you make a page simple enough and do not include any third-party libraries, there is no problem with adding functions at the top level.\n\n#### Tables as layout elements\n\nWhile, of course, the results table is rendered using an HTML `\u003ctable\u003e` element, the form's fieldset is as well, in order to provide a columnar layout between the field labels and the fields themselves. This is the simplest way to ensure that the input fields line up vertically in a column.\n\nWhen printing the search results, the header row on the table is repeated if the results span more than one page.\n\n#### HTML input validation attributes\n\n```html\n\u003cinput type=\"range\" required min=\"5\" max=\"100\" step=\"1\"\u003e\n\n\u003cinput type=\"text\" pattern=\"[A-Za-z]{3}\" title=\"Three letter country code\"\u003e\n```\n\nForms inputs have attributes available like `required`, `min`, `max`, `step`, `pattern`, and `maxlength` that browsers will automatically provide validation and prevent submission with improper values. There is no Javascript required to have contextual form validation when the input fields are designed around what is available by the browser.\n\nThe second example is not used in this application but it shows a very powerful feature of HTML that is seldomly used. If the regular expression is not matched, the browser will display a popup tip containing the `title` attribute as a clue to the user how to fix their input value.\n\n#### No AJAX anywhere\n\n```html\n\u003cform method=\"GET\"\u003e\n```\n\nThe form submits and the page reloads with the results. The user can press the back button and see their previous search. A bookmark of the search results can be made to come back to the same page at a later time. These are all standard browser behaviors that have always existed and we should embrace them without recreating them using complicated Javascript.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnumtel%2Fbeach-report-lite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnumtel%2Fbeach-report-lite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnumtel%2Fbeach-report-lite/lists"}