Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ speed-measure-plugin.json
/.sass-cache
/connect.lock
/coverage
/test-results
/libpeerconnection.log
npm-debug.log
yarn-error.log
Expand Down
19 changes: 8 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</p>

<p align="center">
A progressive Hacker News client built with Angular
A progressive Hacker News client built with React
</p>

<p align="center">
Expand Down Expand Up @@ -43,11 +43,11 @@

## Offline Support

This app uses [Workbox](https://workboxjs.org/) to generate a service worker as part of the build step to load quickly and work offline.
This app uses [Workbox](https://workboxjs.org/) via `vite-plugin-pwa` to generate a service worker as part of the build step to load quickly and work offline.

## Manifest

With Chromium based browsers for Android (Chrome, Opera, etc...), Angular 2 HN includes a Web App Manifest that allows you to install to your homescreen.
With Chromium based browsers for Android (Chrome, Opera, etc...), the app includes a Web App Manifest that allows you to install to your homescreen.

<p align="center">
<img src = "http://i.imgur.com/1RaaNkr.png">
Expand All @@ -73,16 +73,13 @@ Feel free to send me feedback on [twitter](https://twitter.com/hdjirdeh) or [fil

## Build process

Note: This project has been ejected (with AOT + production settings) in order to customize Webpack configurations.

- Clone or download the repo
- `npm install`
- `npm start` to run the application with webpack-dev-server or `npm build` to kick off a fresh build and update the output directory (`dist/`)

Note: Any Service Worker changes will not be reflected when you run the application locally in development. To test service worker changes:
- `npm build`
- `npm run precache` to generate the service worker file
- `npm run static-serve` to load the application along with the service worker asset using [live-server](https://github.com/tapio/live-server)
- `npm start` to run the Vite development server
- `npm run build` to create the production output in `dist/`
- `npm run test` to run Vitest unit tests
- `npm run lint` to run ESLint
- `npm run e2e` to run Playwright browser tests against the preview build

## Contributors

Expand Down
134 changes: 0 additions & 134 deletions angular.json

This file was deleted.

12 changes: 0 additions & 12 deletions browserslist

This file was deleted.

30 changes: 30 additions & 0 deletions e2e-tests/app.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { test, expect } from '@playwright/test';

const item = (id: number) => ({ id, title: `Mock story ${id}`, points: 10, user: 'alice', time: 1, time_ago: '1 hour ago', type: 'story', url: '', domain: '', comments: [], comments_count: 1, poll: [], poll_votes_count: 0, deleted: false, dead: false });

test.beforeEach(async ({ page }) => {
await page.route(/node-hnapi\.herokuapp\.com\/(news|item)(?:\/|\?)/, (route) => {
if (route.request().url().includes('/news?page=1')) {
return route.fulfill({ json: Array.from({ length: 30 }, (_, i) => item(i + 1)) });
}
return route.fulfill({ json: { ...item(1), content: '<p>Details</p>', comments: [{ id: 2, user: 'bob', time_ago: 'now', content: 'A comment', comments: [], deleted: false }] } });
});
});

test('loads the news feed and navigates to an item', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveURL(/\/news\/1$/);
await expect(page.getByRole('link', { name: 'new' })).toBeVisible();
await expect(page.getByRole('link', { name: 'Mock story 1', exact: true })).toBeVisible();
await page.getByRole('link', { name: 'Mock story 1', exact: true }).click();
await expect(page).toHaveURL(/\/item\/1$/);
await expect(page.getByText('A comment')).toBeVisible();
});

test('opens settings and switches theme', async ({ page }) => {
await page.goto('/news/1');
await page.getByRole('button', { name: 'Settings' }).click();
await expect(page.getByRole('heading', { name: 'Settings' })).toBeVisible();
await page.getByLabel('Night').check();
await expect(page.locator('body > #root > .night')).toBeVisible();
});
32 changes: 0 additions & 32 deletions e2e/protractor.conf.js

This file was deleted.

23 changes: 0 additions & 23 deletions e2e/src/app.e2e-spec.ts

This file was deleted.

11 changes: 0 additions & 11 deletions e2e/src/app.po.ts

This file was deleted.

13 changes: 0 additions & 13 deletions e2e/tsconfig.json

This file was deleted.

18 changes: 18 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import eslint from '@eslint/js';
import reactHooks from 'eslint-plugin-react-hooks';
import tseslint from 'typescript-eslint';

export default tseslint.config(
{ ignores: ['dist/**', 'node_modules/**', 'playwright-report/**', 'test-results/**'] },
eslint.configs.recommended,
...tseslint.configs.recommended,
{
files: ['**/*.{ts,tsx}'],
plugins: { 'react-hooks': reactHooks },
rules: {
...reactHooks.configs.recommended.rules,
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
},
);
50 changes: 50 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular 2 HN</title>
<meta name="description" content="A Hacker News client built with Angular CLI, RxJS and Webpack">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@hdjirdeh">
<meta name="twitter:title" content="Angular 2 HN">
<meta name="twitter:description" content="A Hacker News client built with Angular CLI, RxJS and Webpack">
<meta name="twitter:creator" content="@hdjirdeh">
<meta name="twitter:image" content="/assets/images/logo.svg">
<meta property="og:title" content="Angular 2 HN">
<meta property="og:type" content="website">
<meta property="og:url" content="https://angular2-hn.firebaseapp.com/">
<meta property="og:image" content="/assets/images/logo.svg">
<meta property="og:description" content="A Hacker News client built with Angular CLI, RxJS and Webpack">
<meta property="og:site_name" content="Angular 2 HN">
<meta property="fb:admins" content="10202985971279760">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#b92b27">
<meta name="msapplication-TileColor" content="#b92b27">
<meta name="msapplication-TileImage" content="/assets/icons/mstile-150x150.png">
<meta name="msapplication-config" content="/assets/icons/browserconfig.xml">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="manifest" href="/manifest.json">
<link rel="mask-icon" href="/assets/icons/safari-pinned-tab.svg" color="#b92b27">
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" href="/assets/icons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/assets/icons/favicon-16x16.png" sizes="16x16">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="120x120" href="/assets/icons/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="152x152" href="/assets/icons/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/assets/icons/apple-touch-icon-180x180.png">
<style>
#skip a { position:absolute; left:-10000px; top:auto; width:1px; height:1px; overflow:hidden; }
#skip a:focus { position:static; width:auto; height:auto; }
</style>
</head>
<body>
<div id="skip"><a href="#content">skip to navigation</a></div>
<div id="root"></div>
<div class="app-loader" id="content">
<img class="logo" src="/assets/images/logo.svg" alt="Logo">
<noscript><h4 style="font-family: 'HelveticaNeue-Light', 'Helvetica Neue Light', 'Helvetica Neue', Helvetica;">Sorry, JavaScript needs to be enabled in order to run this application.</h4></noscript>
</div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading