eslint & prettier setup

This commit is contained in:
Gyen Abubakar 2022-11-11 16:11:34 +00:00 committed by Robert
parent 7c42805787
commit 5e2ab86e22
10 changed files with 144 additions and 69 deletions

View file

@ -1,16 +1,16 @@
module.exports = {
extends: ['standard-with-typescript', 'standard-jsx'],
extends: ["standard-with-typescript", "standard-jsx", "prettier"],
parserOptions: {
project: './tsconfig.json'
project: "./tsconfig.json",
},
rules: {
'@typescript-eslint/semi': ['error', 'always'],
'@typescript-eslint/no-extra-semi': 'error',
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/strict-boolean-expressions': 0,
'@typescript-eslint/no-floating-promises': 0,
'@typescript-eslint/prefer-nullish-coalescing': 0,
'no-useless-return': 0,
'@typescript-eslint/restrict-template-expressions': 0
}
}
"@typescript-eslint/semi": ["error", "always"],
"@typescript-eslint/no-extra-semi": "error",
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/strict-boolean-expressions": 0,
"@typescript-eslint/no-floating-promises": 0,
"@typescript-eslint/prefer-nullish-coalescing": 0,
"no-useless-return": 0,
"@typescript-eslint/restrict-template-expressions": 0,
},
};

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ tmp/
node_modules/
*.log
.env
.idea

8
.prettierignore Normal file
View file

@ -0,0 +1,8 @@
node_modules
# Ignore artifacts:
build
tmp
.idea
coverage
src/ar
src/en

8
.prettierrc Normal file
View file

@ -0,0 +1,8 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": false,
"printWidth": 80,
"arrowParens": "avoid"
}

View file

@ -131,6 +131,7 @@ GEM
zeitwerk (2.6.1)
PLATFORMS
arm64-darwin-22
x86_64-freebsd-13
DEPENDENCIES

44
package-lock.json generated
View file

@ -1,5 +1,5 @@
{
"name": "al-quran.0x1eef.test",
"name": "al-quran",
"lockfileVersion": 2,
"requires": true,
"packages": {
@ -10,6 +10,8 @@
"classnames": "^2.3.2",
"es-cookie": "^1.4.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-loader": "^9.3.1",
@ -1318,6 +1320,18 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-config-prettier": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
"dev": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-config-standard": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz",
@ -3265,6 +3279,21 @@
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@ -5350,6 +5379,13 @@
}
}
},
"eslint-config-prettier": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
"integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
"dev": true,
"requires": {}
},
"eslint-config-standard": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz",
@ -6654,6 +6690,12 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true
},
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"dev": true
},
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",

View file

@ -8,6 +8,8 @@
"classnames": "^2.3.2",
"es-cookie": "^1.4.0",
"eslint": "^8.26.0",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-loader": "^9.3.1",

View file

@ -1,30 +1,35 @@
import { Surah, Ayat, Ayah } from 'lib/Quran';
import React, { useEffect } from 'react';
import classNames from 'classnames';
import { Surah, Ayat, Ayah } from "lib/Quran";
import React, { useEffect } from "react";
import classNames from "classnames";
interface StreamProps {
surah: Surah
stream: Ayat
surah: Surah;
stream: Ayat;
}
export function Stream ({ surah, stream }: StreamProps) {
export function Stream({ surah, stream }: StreamProps) {
const endOfStream = stream.length === surah.ayat.length;
const ayat = stream.map((ayah: Ayah) => {
return (
<li key={ayah.id} className='ayah fade'>
<span>Surah {surah.id}, Ayah {ayah.id}</span>
<li key={ayah.id} className="ayah fade">
<span>
Surah {surah.id}, Ayah {ayah.id}
</span>
<p>{ayah.text}</p>
</li>
);
});
useEffect(() => {
const el: HTMLElement = document.querySelector('ul.stream');
el.scroll({ top: el.offsetHeight * stream.length, behavior: 'smooth' });
const el: HTMLElement = document.querySelector("ul.stream");
el.scroll({
top: el.offsetHeight * stream.length,
behavior: "smooth",
});
}, [stream]);
return (
<ul className={classNames('stream', { 'scroll-y': endOfStream })}>
<ul className={classNames("stream", { "scroll-y": endOfStream })}>
{ayat}
</ul>
);

View file

@ -1,58 +1,64 @@
interface SurahDetails {
id: string
place_of_revelation: string
transliterated_name: string
translated_name: string
verse_count: number
slug: string
codepoints: number[]
id: string;
place_of_revelation: string;
transliterated_name: string;
translated_name: string;
verse_count: number;
slug: string;
codepoints: number[];
}
export interface Ayah {id: number, text: string, readTimeMs: number}
export interface Ayah {
id: number;
text: string;
readTimeMs: number;
}
export type Ayat = Ayah[];
export class Surah {
#details: SurahDetails;
ayat: Ayat;
static fromJSON (details: SurahDetails, ayat: Array<[number, string]>): Surah {
static fromJSON(details: SurahDetails, ayat: Array<[number, string]>): Surah {
return new Surah(
details,
ayat.map(([id, text]) => {
return {
id,
text,
readTimeMs: text.split(' ').length * 500
readTimeMs: text.split(" ").length * 500,
};
})
}),
);
}
constructor (details: SurahDetails, ayat: Ayat) {
constructor(details: SurahDetails, ayat: Ayat) {
this.#details = details;
this.ayat = ayat;
}
get id () {
get id() {
return this.#details.id;
}
get name () {
get name() {
return String.fromCodePoint(...this.#details.codepoints);
}
get transliteratedName () {
get transliteratedName() {
return this.#details.transliterated_name;
}
get translatedName () {
get translatedName() {
return this.#details.translated_name;
}
get placeOfRevelation () {
get placeOfRevelation() {
return this.#details.place_of_revelation;
}
get numberOfAyah () {
get numberOfAyah() {
return this.#details.verse_count;
}
}

View file

@ -1,61 +1,63 @@
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import useSurah from 'hooks/useSurah';
import { Timer } from 'components/TheQuran/Timer';
import { Stream } from 'components/TheQuran/Stream';
import { AboutSurah } from 'components/TheQuran/AboutSurah';
import { ThemeSelect } from 'components/TheQuran/ThemeSelect';
import classNames from 'classnames';
import { get as getCookie } from 'es-cookie';
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";
import useSurah from "hooks/useSurah";
import { Timer } from "components/TheQuran/Timer";
import { Stream } from "components/TheQuran/Stream";
import { AboutSurah } from "components/TheQuran/AboutSurah";
import { ThemeSelect } from "components/TheQuran/ThemeSelect";
import classNames from "classnames";
import { get as getCookie } from "es-cookie";
interface PageProps {
locale: string
surahId: number
locale: string;
surahId: number;
}
function TheSurahPage ({ locale, surahId }: PageProps) {
function TheSurahPage({ locale, surahId }: PageProps) {
const { surahIsLoaded, surah } = useSurah(locale, surahId);
const [stream, setStream] = useState([]);
const [theme, setTheme] = useState(getCookie('theme') || 'moon');
const [theme, setTheme] = useState(getCookie("theme") || "moon");
const streamIsLoaded = !(stream.length === 0);
useEffect(() => {
if (surahIsLoaded) {
document.title = [
'Al-Quran:',
"Al-Quran:",
surah.transliteratedName,
`(${surah.translatedName})`
].join(' ');
`(${surah.translatedName})`,
].join(" ");
setStream([surah.ayat[stream.length]]);
}
}, [surahIsLoaded]);
return (
<div className={classNames(theme, locale, 'theme')}>
<div className='flex-image'>
<div className='image' />
<div className={classNames(theme, "theme")}>
<div className="flex-image">
<div className="image" />
</div>
{streamIsLoaded &&
<div className='flex-row'>
{streamIsLoaded && (
<div className="flex-row">
<span />
<ThemeSelect theme={theme} setTheme={setTheme} />
<span />
</div>}
</div>
)}
{streamIsLoaded && <AboutSurah surah={surah} />}
{streamIsLoaded && <Stream surah={surah} stream={stream} />}
{streamIsLoaded && stream.length < surah.numberOfAyah &&
{streamIsLoaded && stream.length < surah.numberOfAyah && (
<Timer
surah={surah}
ayah={surah.ayat[stream.length - 1]}
setStream={setStream}
stream={stream}
/>}
/>
)}
</div>
);
}
const el = document.querySelector('.surah');
const locale = el.getAttribute('data-locale');
const surahId = parseInt(el.getAttribute('data-surah-id'));
const el = document.querySelector(".surah");
const locale = el.getAttribute("data-locale");
const surahId = parseInt(el.getAttribute("data-surah-id"));
const root = ReactDOM.createRoot(el);
root.render(<TheSurahPage locale={locale} surahId={surahId} />);