chore: delete template files

This commit is contained in:
Paul Pan 2024-03-16 17:41:34 +08:00
parent ac8e3ab972
commit 0be3286bb3
7 changed files with 0 additions and 350 deletions

View File

@ -1,79 +0,0 @@
.row {
display: flex;
align-items: center;
justify-content: center;
}
.row > button {
margin-left: 4px;
margin-right: 8px;
}
.row:not(:last-child) {
margin-bottom: 16px;
}
.value {
font-size: 78px;
padding-left: 16px;
padding-right: 16px;
margin-top: 2px;
font-family: "Courier New", Courier, monospace;
}
.button {
appearance: none;
font-size: 32px;
padding-left: 12px;
padding-right: 12px;
outline: none;
border: 2px solid transparent;
color: rgb(112, 76, 182);
padding-bottom: 4px;
cursor: pointer;
background: rgba(112, 76, 182, 0.1) none;
border-radius: 2px;
transition: all 0.15s;
}
.textbox {
font-size: 32px;
padding: 2px;
width: 64px;
text-align: center;
margin-right: 4px;
}
.button:hover,
.button:focus {
border: 2px solid rgba(112, 76, 182, 0.4);
}
.button:active {
background-color: rgba(112, 76, 182, 0.2);
}
.asyncButton {
composes: button;
position: relative;
}
.asyncButton:after {
content: "";
background-color: rgba(112, 76, 182, 0.15);
display: block;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
opacity: 0;
transition: width 1s linear,
opacity 0.5s ease 1s;
}
.asyncButton:active:after {
width: 0;
opacity: 1;
transition: 0s;
}

View File

@ -1,67 +0,0 @@
import { useState } from "react";
import { useAppDispatch, useAppSelector } from "../../hooks/store";
import styles from "./Counter.module.css";
import {
decrement,
increment,
incrementAsync,
incrementByAmount,
incrementIfOdd,
selectCount,
selectStatus,
} from "./counterSlice";
export const Counter = () => {
const dispatch = useAppDispatch();
const count = useAppSelector(selectCount);
const status = useAppSelector(selectStatus);
const [incrementAmount, setIncrementAmount] = useState("2");
const incrementValue = Number(incrementAmount) || 0;
return (
<div>
<div className={styles.row}>
<button className={styles.button} aria-label="Decrement value" onClick={() => dispatch(decrement())}>
-
</button>
<span aria-label="Count" className={styles.value}>
{count}
</span>
<button className={styles.button} aria-label="Increment value" onClick={() => dispatch(increment())}>
+
</button>
</div>
<div className={styles.row}>
<input
className={styles.textbox}
aria-label="Set increment amount"
value={incrementAmount}
type="number"
onChange={(e) => {
setIncrementAmount(e.target.value);
}}
/>
<button className={styles.button} onClick={() => dispatch(incrementByAmount(incrementValue))}>
Add Amount
</button>
<button
className={styles.asyncButton}
disabled={status !== "idle"}
onClick={() => void dispatch(incrementAsync(incrementValue))}
>
Add Async
</button>
<button
className={styles.button}
onClick={() => {
dispatch(incrementIfOdd(incrementValue));
}}
>
Add If Odd
</button>
</div>
</div>
);
};

View File

@ -1,4 +0,0 @@
// A mock function to mimic making an async request for data
export const fetchCount = (amount = 1) => {
return new Promise<{ data: number }>((resolve) => setTimeout(() => resolve({ data: amount }), 500));
};

View File

@ -1,86 +0,0 @@
import type { PayloadAction } from "@reduxjs/toolkit";
import { createAppSlice } from "../../app/createAppSlice";
import type { AppThunk } from "../../app/store";
import { fetchCount } from "./counterAPI";
export interface CounterSliceState {
value: number;
status: "idle" | "loading" | "failed";
}
const initialState: CounterSliceState = {
value: 0,
status: "idle",
};
// If you are not using async thunks you can use the standalone `createSlice`.
export const counterSlice = createAppSlice({
name: "counter",
// `createSlice` will infer the state type from the `initialState` argument
initialState,
// The `reducers` field lets us define reducers and generate associated actions
reducers: (create) => ({
increment: create.reducer((state) => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1;
}),
decrement: create.reducer((state) => {
state.value -= 1;
}),
// Use the `PayloadAction` type to declare the contents of `action.payload`
incrementByAmount: create.reducer((state, action: PayloadAction<number>) => {
state.value += action.payload;
}),
// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
incrementAsync: create.asyncThunk(
async (amount: number) => {
const response = await fetchCount(amount);
// The value we return becomes the `fulfilled` action payload
return response.data;
},
{
pending: (state) => {
state.status = "loading";
},
fulfilled: (state, action) => {
state.status = "idle";
state.value += action.payload;
},
rejected: (state) => {
state.status = "failed";
},
},
),
}),
// You can define your selectors here. These selectors receive the slice
// state as their first argument.
selectors: {
selectCount: (counter) => counter.value,
selectStatus: (counter) => counter.status,
},
});
// Action creators are generated for each case reducer function.
export const { decrement, increment, incrementByAmount, incrementAsync } = counterSlice.actions;
// Selectors returned by `slice.selectors` take the root state as their first argument.
export const { selectCount, selectStatus } = counterSlice.selectors;
// We can also write thunks by hand, which may contain both sync and async logic.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd =
(amount: number): AppThunk =>
(dispatch, getState) => {
const currentValue = selectCount(getState());
if (currentValue % 2 === 1 || currentValue % 2 === -1) {
dispatch(incrementByAmount(amount));
}
};

View File

@ -1,18 +0,0 @@
.select {
font-size: 25px;
padding: 2px 5px;
size: 50px;
outline: none;
border: 2px solid transparent;
color: rgb(112, 76, 182);
cursor: pointer;
background-color: rgba(112, 76, 182, 0.1);
border-radius: 5px;
transition: all 0.15s;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
}

View File

@ -1,58 +0,0 @@
import { useState } from "react";
import styles from "./Quotes.module.css";
import { useGetQuotesQuery } from "./quotesApiSlice";
const options = [5, 10, 20, 30];
export const Quotes = () => {
const [numberOfQuotes, setNumberOfQuotes] = useState(10);
// Using a query hook automatically fetches data and returns query values
const { data, isError, isLoading, isSuccess } = useGetQuotesQuery(numberOfQuotes);
if (isError) {
return (
<div>
<h1>There was an error!!!</h1>
</div>
);
}
if (isLoading) {
return (
<div>
<h1>Loading...</h1>
</div>
);
}
if (isSuccess) {
return (
<div className={styles.container}>
<h3>Select the Quantity of Quotes to Fetch:</h3>
<select
className={styles.select}
value={numberOfQuotes}
onChange={(e) => {
setNumberOfQuotes(Number(e.target.value));
}}
>
{options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
{data.quotes.map(({ author, quote, id }) => (
<blockquote key={id}>
&ldquo;{quote}&rdquo;
<footer>
<cite>{author}</cite>
</footer>
</blockquote>
))}
</div>
);
}
return null;
};

View File

@ -1,38 +0,0 @@
// Need to use the React-specific entry point to import `createApi`
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
interface Quote {
id: number;
quote: string;
author: string;
}
interface QuotesApiResponse {
quotes: Quote[];
total: number;
skip: number;
limit: number;
}
// Define a service using a base URL and expected endpoints
export const quotesApiSlice = createApi({
baseQuery: fetchBaseQuery({ baseUrl: "https://dummyjson.com/quotes" }),
reducerPath: "quotesApi",
// Tag types are used for caching and invalidation.
tagTypes: ["Quotes"],
endpoints: (build) => ({
// Supply generics for the return type (in this case `QuotesApiResponse`)
// and the expected query argument. If there is no argument, use `void`
// for the argument type instead.
getQuotes: build.query<QuotesApiResponse, number>({
query: (limit = 10) => `?limit=${limit}`,
// `providesTags` determines which 'tag' is attached to the
// cached data returned by the query.
providesTags: (result, error, id) => [{ type: "Quotes", id }],
}),
}),
});
// Hooks are auto-generated by RTK-Query
// Same as `quotesApiSlice.endpoints.getQuotes.useQuery`
export const { useGetQuotesQuery } = quotesApiSlice;