Skip to content

Commit

Permalink
fix accessibility and performance analysis
Browse files Browse the repository at this point in the history
  • Loading branch information
Ambrozy committed Nov 5, 2024
1 parent 60440c3 commit 7a4a4f5
Show file tree
Hide file tree
Showing 19 changed files with 100 additions and 67 deletions.
Binary file modified bun.lockb
Binary file not shown.
8 changes: 8 additions & 0 deletions docs/accessibility.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Icons in headings do not have any functional meaning, so they should be hidden from screen readers.

Weather icons represent the weather condition, so we should add a title attribute to them to ensure screen readers can
properly interpret the icons.

For the day name, minimum, and maximum temperature, we should add appropriate title attributes.

Chrome DevTools has accessibility tree to track what screen readers see.
Binary file added docs/desktop-performance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/mobile-performance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions docs/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Pagespeed analysis:
https://pagespeed.web.dev/analysis/
![mobile performance](./mobile-performance.png)
![desktop performance](./desktop-performance.png)
The long Layout Shift on mobile devices may be due to the fact that we do not render the application until localStorage
returns the initial data to us, but overall the value is in the yellow zone.
3 changes: 3 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import jsxA11y from "eslint-plugin-jsx-a11y";
import tseslint from "typescript-eslint";

export default tseslint.config(
Expand All @@ -16,13 +17,15 @@ export default tseslint.config(
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
"jsx-a11y": jsxA11y,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
...jsxA11y.flatConfigs.recommended.rules,
},
},
);
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@vite-pwa/assets-generator": "^0.2.6",
"@vitejs/plugin-react": "^4.3.3",
"eslint": "^9.13.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.13",
"globals": "^15.11.0",
Expand Down
5 changes: 3 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ Install `bun` package manager globally. [Bun docs](https://bun.sh/)
current state.
3. **Accessibility**.
- Support screen readers, markup with ARIA labels.
- Navigate the app using a keyboard (left-right scrolling for hourly forecast, up-down scrolling for 10-day
forecast).
- Navigate the app using a keyboard (up-down - vertical scrolling).
- Scroll area covers entire content, not just scrollbar.
- Using of contrast colors.
4. **API limitation**.
Expand Down Expand Up @@ -143,6 +142,8 @@ demo application, a free API key is used, and no proxy backend has been implemen
5. If we want to switch the background depending on the time of day, simply changing the background is not sufficient.
The text and other elements become difficult to read. Therefore, it is necessary to adjust them and request the
designer to create different screen versions. A good solution here would be to use themes.
6. [accessibility.md](docs%2Faccessibility.md)
7. [performance.md](docs%2Fperformance.md)

# Ideas for further project development:

Expand Down
14 changes: 7 additions & 7 deletions src/components/AccuWeatherIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ export const AccuWeatherIcon = memo(
case 1:
case 2:
case 3:
return <Sunny />;
return <Sunny role="img" title="Sunny" />;
case 4:
case 5:
case 6:
case 20:
case 21:
case 23:
return <Cloudy />;
return <Cloudy role="img" title="Cloudy" />;
case 7:
case 8:
case 11:
Expand All @@ -41,28 +41,28 @@ export const AccuWeatherIcon = memo(
case 36:
case 37:
case 38:
return <NightCloudy />;
return <NightCloudy role="img" title="Night Cloudy" />;
case 12:
case 13:
case 14:
return <LightRain />;
return <LightRain role="img" title="Light Rain" />;
case 15:
case 16:
case 17:
return <Thunder />;
return <Thunder role="img" title="Thunder" />;
case 18:
case 22:
case 25:
case 26:
case 29:
return <Rain />;
return <Rain role="img" title="Rain" />;
case 39:
case 40:
case 41:
case 42:
case 43:
case 44:
return <HeavyRain />;
return <HeavyRain role="img" title="Heavy Rain" />;
default:
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ export const AppHeader = memo(
{locationName}
{isError && (
<IconContainerS>
<Warning />
<Warning role="img" title="The weather forecast is out of date" />
</IconContainerS>
)}
{isLoading && (
<IconContainerS>
<LoaderS />
<LoaderS role="img" title="Loading weather forecast" />
</IconContainerS>
)}
</LocationS>
Expand Down
2 changes: 1 addition & 1 deletion src/components/AppWelcomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const AppWelcomeScreenS = styled.div<{ $isError: boolean }>`

export const AppWelcomeScreen = memo(({ isError }: AppWelcomeScreenProps) => (
<AppWelcomeScreenS $isError={isError}>
<Sunny />
<Sunny aria-hidden={isError} role="img" title="Loading weather forecast" />
{isError && (
<div>
Failed to load data, <br /> try again later
Expand Down
63 changes: 33 additions & 30 deletions src/components/DailyForecastPanelItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,36 +36,39 @@ export const DailyForecastPanelItem = memo(
hasPrecipitation,
precipitationProbability,
isToday,
}: DailyForecastPanelItemProps) => (
<DailyForecastRowS>
<DailyForecastTimeS>
{isToday ? "Today" : formatDay(dateTime)}
</DailyForecastTimeS>
}: DailyForecastPanelItemProps) => {
const dayTitle = isToday ? "Today" : formatDay(dateTime);
const dayText = isToday ? "Today" : formatDay(dateTime)?.slice(0, 3);

{hasPrecipitation ? (
<DailyForecastConditionsWithPrecipitationS>
<AccuWeatherIcon iconIndex={iconIndex} />
<DailyForecastProbabilityS>
{precipitationProbability}%
</DailyForecastProbabilityS>
</DailyForecastConditionsWithPrecipitationS>
) : (
<DailyForecastConditionsS>
<AccuWeatherIcon iconIndex={iconIndex} />
</DailyForecastConditionsS>
)}
return (
<DailyForecastRowS>
<DailyForecastTimeS title={dayTitle}>{dayText}</DailyForecastTimeS>

<DailyRange
temperature={
hasAverageTemperature
? (minTemperature + maxTemperature) / 2
: undefined
}
totalMinTemperature={totalMinTemperature}
totalMaxTemperature={totalMaxTemperature}
minTemperature={minTemperature}
maxTemperature={maxTemperature}
/>
</DailyForecastRowS>
),
{hasPrecipitation ? (
<DailyForecastConditionsWithPrecipitationS>
<AccuWeatherIcon iconIndex={iconIndex} />
<DailyForecastProbabilityS>
{precipitationProbability}%
</DailyForecastProbabilityS>
</DailyForecastConditionsWithPrecipitationS>
) : (
<DailyForecastConditionsS>
<AccuWeatherIcon iconIndex={iconIndex} />
</DailyForecastConditionsS>
)}

<DailyRange
temperature={
hasAverageTemperature
? (minTemperature + maxTemperature) / 2
: undefined
}
totalMinTemperature={totalMinTemperature}
totalMaxTemperature={totalMaxTemperature}
minTemperature={minTemperature}
maxTemperature={maxTemperature}
/>
</DailyForecastRowS>
);
},
);
4 changes: 2 additions & 2 deletions src/components/DailyRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export const DailyRange = memo(

return (
<DailyRangeS>
<DailyMinTemperatureS>
<DailyMinTemperatureS title="Minimum Temperature">
{formatTemperature(minTemperature)}
</DailyMinTemperatureS>
<RangeS>
<RangeMeterS $left={rangeLeft} $right={rangeRight} />
{temperature !== undefined && <CurrentMarkS $left={markerLeft} />}
</RangeS>
<DailyMaxTemperatureS>
<DailyMaxTemperatureS title="Maximum Temperature">
{formatTemperature(maxTemperature)}
</DailyMaxTemperatureS>
</DailyRangeS>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ForecastPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ForecastTitleS = styled.div`
export const ForecastPanel = memo(({ title, children }: ForecastPanelProps) => (
<ForecastS>
<ForecastTitleS>
<Calendar /> {title}
<Calendar aria-hidden="true" /> {title}
</ForecastTitleS>
{children}
</ForecastS>
Expand Down
28 changes: 14 additions & 14 deletions src/components/utils/formatDay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ import { it, describe, expect } from "vitest";
import { formatDay } from "./formatDay.ts";

describe("formatDay", () => {
it("should return Mon", () => {
expect(formatDay("2024-11-04T00:00:00+01:00")).toBe("Mon");
it("should return Monday", () => {
expect(formatDay("2024-11-04T00:00:00+01:00")).toBe("Monday");
});
it("should return Tue", () => {
expect(formatDay("2024-11-05T00:00:00+01:00")).toBe("Tue");
it("should return Tuesday", () => {
expect(formatDay("2024-11-05T00:00:00+01:00")).toBe("Tuesday");
});
it("should return Wed", () => {
expect(formatDay("2024-11-06T00:00:00+01:00")).toBe("Wed");
it("should return Wednesday", () => {
expect(formatDay("2024-11-06T00:00:00+01:00")).toBe("Wednesday");
});
it("should return Thu", () => {
expect(formatDay("2024-11-07T00:00:00+01:00")).toBe("Thu");
it("should return Thursday", () => {
expect(formatDay("2024-11-07T00:00:00+01:00")).toBe("Thursday");
});
it("should return Fri", () => {
expect(formatDay("2024-11-08T00:00:00+01:00")).toBe("Fri");
it("should return Friday", () => {
expect(formatDay("2024-11-08T00:00:00+01:00")).toBe("Friday");
});
it("should return Sat", () => {
expect(formatDay("2024-11-09T00:00:00+01:00")).toBe("Sat");
it("should return Saturday", () => {
expect(formatDay("2024-11-09T00:00:00+01:00")).toBe("Saturday");
});
it("should return Sun", () => {
expect(formatDay("2024-11-10T00:00:00+01:00")).toBe("Sun");
it("should return Sunday", () => {
expect(formatDay("2024-11-10T00:00:00+01:00")).toBe("Sunday");
});
});
14 changes: 7 additions & 7 deletions src/components/utils/formatDay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ export const formatDay = (dateTime: string) => {
const weekDay = new Date(dateTime).getDay();

return {
0: "Sun",
1: "Mon",
2: "Tue",
3: "Wed",
4: "Thu",
5: "Fri",
6: "Sat",
0: "Sunday",
1: "Monday",
2: "Tuesday",
3: "Wednesday",
4: "Thursday",
5: "Friday",
6: "Saturday",
}[weekDay];
};
3 changes: 3 additions & 0 deletions tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"files": [
"types/base.d.ts"
],
"include": [
"src"
]
Expand Down
8 changes: 8 additions & 0 deletions types/base.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

declare module "*.svg" {
import type { ReactElement, HTMLAttributes } from "react";

const content: (props: HTMLAttributes<HTMLDivElement>) => ReactElement;

export default content;
}
2 changes: 1 addition & 1 deletion vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default defineConfig({
exportType: "default",
ref: true,
svgo: false,
titleProp: true,
titleProp: true, // a11y for svg, add `title` tag content by setting component `title` attribute
},
include: "**/*.svg",
}),
Expand Down

0 comments on commit 7a4a4f5

Please sign in to comment.