Add settings, cards list, card preview views
* Settings view is no longer the card creation view * Add icons for the two settings options
This commit is contained in:
		
							parent
							
								
									1abf35b35f
								
							
						
					
					
						commit
						b21ec1b7ac
					
				
							
								
								
									
										9
									
								
								public/icons/file-plus.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								public/icons/file-plus.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-file-plus" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
 | 
				
			||||||
 | 
					  <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
 | 
				
			||||||
 | 
					  <path d="M14 3v4a1 1 0 0 0 1 1h4" />
 | 
				
			||||||
 | 
					  <path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z" />
 | 
				
			||||||
 | 
					  <line x1="12" y1="11" x2="12" y2="17" />
 | 
				
			||||||
 | 
					  <line x1="9" y1="14" x2="15" y2="14" />
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 502 B  | 
							
								
								
									
										11
									
								
								public/icons/list.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								public/icons/list.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-list" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
 | 
				
			||||||
 | 
					  <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
 | 
				
			||||||
 | 
					  <line x1="9" y1="6" x2="20" y2="6" />
 | 
				
			||||||
 | 
					  <line x1="9" y1="12" x2="20" y2="12" />
 | 
				
			||||||
 | 
					  <line x1="9" y1="18" x2="20" y2="18" />
 | 
				
			||||||
 | 
					  <line x1="5" y1="6" x2="5" y2="6.01" />
 | 
				
			||||||
 | 
					  <line x1="5" y1="12" x2="5" y2="12.01" />
 | 
				
			||||||
 | 
					  <line x1="5" y1="18" x2="5" y2="18.01" />
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 541 B  | 
@ -6,7 +6,10 @@ import {
 | 
				
			|||||||
  ExpressionSetListView,
 | 
					  ExpressionSetListView,
 | 
				
			||||||
} from "../../views";
 | 
					} from "../../views";
 | 
				
			||||||
import { AddExpressionView } from "../../views/AddExpressionView";
 | 
					import { AddExpressionView } from "../../views/AddExpressionView";
 | 
				
			||||||
 | 
					import { ExpressionCardListView } from "../../views/ExpressionCardListView";
 | 
				
			||||||
 | 
					import { ExpressionCardView } from "../../views/ExpressionCardView";
 | 
				
			||||||
import { HomeView } from "../../views/HomeView";
 | 
					import { HomeView } from "../../views/HomeView";
 | 
				
			||||||
 | 
					import { SettingsView } from "../../views/SettingsView";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function Page() {
 | 
					export function Page() {
 | 
				
			||||||
  const { route } = useContext(AppRouting);
 | 
					  const { route } = useContext(AppRouting);
 | 
				
			||||||
@ -22,7 +25,12 @@ export function Page() {
 | 
				
			|||||||
    case AppPath.ExpressionSetsPractice:
 | 
					    case AppPath.ExpressionSetsPractice:
 | 
				
			||||||
      return <ExpressionPracticeView />;
 | 
					      return <ExpressionPracticeView />;
 | 
				
			||||||
    case AppPath.Settings:
 | 
					    case AppPath.Settings:
 | 
				
			||||||
      // TODO this should split onto more views
 | 
					      return <SettingsView />;
 | 
				
			||||||
 | 
					    case AppPath.CreateCards:
 | 
				
			||||||
      return <AddExpressionView />;
 | 
					      return <AddExpressionView />;
 | 
				
			||||||
 | 
					    case AppPath.CardsList:
 | 
				
			||||||
 | 
					      return <ExpressionCardListView />;
 | 
				
			||||||
 | 
					    case AppPath.CardView:
 | 
				
			||||||
 | 
					      return <ExpressionCardView />;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/components/SettingsSection/SettingsSectionLink.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/components/SettingsSection/SettingsSectionLink.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { useContext } from "react";
 | 
				
			||||||
 | 
					import { AppPath, AppRouting } from "../../model/routing";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface SettingsSectionLinkProps {
 | 
				
			||||||
 | 
					  text: string;
 | 
				
			||||||
 | 
					  iconUrl?: string;
 | 
				
			||||||
 | 
					  page: AppPath;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function SettingsSectionLink({
 | 
				
			||||||
 | 
					  text,
 | 
				
			||||||
 | 
					  iconUrl,
 | 
				
			||||||
 | 
					  page,
 | 
				
			||||||
 | 
					}: SettingsSectionLinkProps) {
 | 
				
			||||||
 | 
					  const { setRoute } = useContext(AppRouting);
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <li onClick={() => setRoute({ path: page })}>
 | 
				
			||||||
 | 
					      <div className="content-card">
 | 
				
			||||||
 | 
					        <div className="content-row">
 | 
				
			||||||
 | 
					          {iconUrl && <img src={iconUrl} width="24" height="24" alt="" />}
 | 
				
			||||||
 | 
					          <h2 className="text-title padding-small">{text}</h2>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </li>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/components/SettingsSection/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/components/SettingsSection/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from "./SettingsSectionLink";
 | 
				
			||||||
@ -1,5 +1,8 @@
 | 
				
			|||||||
export * from "./useExpressionCategories";
 | 
					export * from "./useExpressionCategories";
 | 
				
			||||||
 | 
					export * from "./useExpressionById";
 | 
				
			||||||
export * from "./useExpressionFilterQueryIds";
 | 
					export * from "./useExpressionFilterQueryIds";
 | 
				
			||||||
 | 
					export * from "./useExpressionQueryId";
 | 
				
			||||||
 | 
					export * from "./useExpressions";
 | 
				
			||||||
export * from "./useExpressionSet";
 | 
					export * from "./useExpressionSet";
 | 
				
			||||||
export * from "./useExpressionSetQueryId";
 | 
					export * from "./useExpressionSetQueryId";
 | 
				
			||||||
export * from "./useExpressionSets";
 | 
					export * from "./useExpressionSets";
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/hooks/useExpressionById.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/hooks/useExpressionById.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { useLiveQuery } from "dexie-react-hooks";
 | 
				
			||||||
 | 
					import { database, IndexedExpression } from "../model";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useExpressionById(id?: number): IndexedExpression | undefined {
 | 
				
			||||||
 | 
					  return useLiveQuery(() => {
 | 
				
			||||||
 | 
					    if (id === undefined) return undefined;
 | 
				
			||||||
 | 
					    return database.expressions.where({ id }).first();
 | 
				
			||||||
 | 
					  }, [id]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								src/hooks/useExpressionQueryId.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/hooks/useExpressionQueryId.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					import { useContext } from "react";
 | 
				
			||||||
 | 
					import { AppRouting } from "../model/routing";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useExpressionQueryId(): number | undefined {
 | 
				
			||||||
 | 
					  const { route } = useContext(AppRouting);
 | 
				
			||||||
 | 
					  return route.options?.expression_card_id;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/hooks/useExpressions.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/hooks/useExpressions.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					import { useLiveQuery } from "dexie-react-hooks";
 | 
				
			||||||
 | 
					import { database } from "../model";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useExpressions() {
 | 
				
			||||||
 | 
					  return useLiveQuery(
 | 
				
			||||||
 | 
					    () => database.expressions.toArray(),
 | 
				
			||||||
 | 
					    [database.expressions]
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -7,10 +7,16 @@ export enum AppPath {
 | 
				
			|||||||
  ExpressionSetsPractice = "expression-sets/practice",
 | 
					  ExpressionSetsPractice = "expression-sets/practice",
 | 
				
			||||||
  ExpressionSetsDetails = "expression-sets/details",
 | 
					  ExpressionSetsDetails = "expression-sets/details",
 | 
				
			||||||
  Settings = "settings",
 | 
					  Settings = "settings",
 | 
				
			||||||
  CreateCards = "settings", // TODO split from settings
 | 
					  CardsList = "settings/cards",
 | 
				
			||||||
 | 
					  CardView = "settings/view-card",
 | 
				
			||||||
 | 
					  CreateCards = "settings/create-cards",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface RouteOptions {
 | 
					export interface RouteOptions {
 | 
				
			||||||
 | 
					  // Used in cards view
 | 
				
			||||||
 | 
					  expression_card_id?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Used in practice view
 | 
				
			||||||
  expression_set_id?: number;
 | 
					  expression_set_id?: number;
 | 
				
			||||||
  expression_id_filters?: number[];
 | 
					  expression_id_filters?: number[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										50
									
								
								src/views/ExpressionCardListView/ExpressionCardListView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/views/ExpressionCardListView/ExpressionCardListView.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					import { useContext, useMemo } from "react";
 | 
				
			||||||
 | 
					import { ExpressionCard } from "../../components";
 | 
				
			||||||
 | 
					import { useExpressions } from "../../hooks";
 | 
				
			||||||
 | 
					import { IndexedExpression } from "../../model";
 | 
				
			||||||
 | 
					import { AppPath, AppRouting } from "../../model/routing";
 | 
				
			||||||
 | 
					import { ErrorView } from "../ErrorView";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ExpressionCardListView() {
 | 
				
			||||||
 | 
					  const { setRoute } = useContext(AppRouting);
 | 
				
			||||||
 | 
					  const expressions = useExpressions();
 | 
				
			||||||
 | 
					  const expression_list = useMemo(
 | 
				
			||||||
 | 
					    () => (expressions || []).concat().sort(sort_function),
 | 
				
			||||||
 | 
					    [expressions]
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!expressions) return null; // LOADING
 | 
				
			||||||
 | 
					  if (!expressions.length) {
 | 
				
			||||||
 | 
					    return <ErrorView message="No expression cards yet" />;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="page-with-padding content-list scroll">
 | 
				
			||||||
 | 
					      <ul className="content-list">
 | 
				
			||||||
 | 
					        {expression_list.map(({ prompt, id, description }) => (
 | 
				
			||||||
 | 
					          <li
 | 
				
			||||||
 | 
					            key={id}
 | 
				
			||||||
 | 
					            onClick={() =>
 | 
				
			||||||
 | 
					              setRoute({
 | 
				
			||||||
 | 
					                path: AppPath.CardView,
 | 
				
			||||||
 | 
					                options: { expression_card_id: id },
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <ExpressionCard
 | 
				
			||||||
 | 
					              prompt={prompt}
 | 
				
			||||||
 | 
					              categories={[]}
 | 
				
			||||||
 | 
					              description={description}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </li>
 | 
				
			||||||
 | 
					        ))}
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function sort_function(a: IndexedExpression, b: IndexedExpression) {
 | 
				
			||||||
 | 
					  if (a.prompt < b.prompt) return -1;
 | 
				
			||||||
 | 
					  if (a.prompt > b.prompt) return 1;
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/views/ExpressionCardListView/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/views/ExpressionCardListView/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from "./ExpressionCardListView";
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/views/ExpressionCardView/ExpressionCardView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/views/ExpressionCardView/ExpressionCardView.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import { ExpressionCard } from "../../components";
 | 
				
			||||||
 | 
					import { ExpressionDescription } from "../../components/ExpressionDescription";
 | 
				
			||||||
 | 
					import { useExpressionById, useExpressionQueryId } from "../../hooks";
 | 
				
			||||||
 | 
					import { ErrorView } from "../ErrorView";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function ExpressionCardView() {
 | 
				
			||||||
 | 
					  const expression_id = useExpressionQueryId();
 | 
				
			||||||
 | 
					  const expression = useExpressionById(expression_id);
 | 
				
			||||||
 | 
					  if (!expression) return <ErrorView message="No valid card selected" />;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="page-with-padding content-list scroll">
 | 
				
			||||||
 | 
					      <ExpressionCard
 | 
				
			||||||
 | 
					        prompt={expression.prompt}
 | 
				
			||||||
 | 
					        categories={[]}
 | 
				
			||||||
 | 
					        description={<ExpressionDescription expression={expression} />}
 | 
				
			||||||
 | 
					        show_description
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/views/ExpressionCardView/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/views/ExpressionCardView/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from "./ExpressionCardView";
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/views/SettingsView/SettingsView.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/views/SettingsView/SettingsView.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import { SettingsSectionLink } from "../../components/SettingsSection";
 | 
				
			||||||
 | 
					import { AppPath } from "../../model/routing";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function SettingsView() {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="page-with-padding content-list scroll">
 | 
				
			||||||
 | 
					      <ul className="content-list">
 | 
				
			||||||
 | 
					        <SettingsSectionLink
 | 
				
			||||||
 | 
					          text="Create cards"
 | 
				
			||||||
 | 
					          page={AppPath.CreateCards}
 | 
				
			||||||
 | 
					          iconUrl="/icons/file-plus.svg"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <SettingsSectionLink
 | 
				
			||||||
 | 
					          text="Cards list"
 | 
				
			||||||
 | 
					          page={AppPath.CardsList}
 | 
				
			||||||
 | 
					          iconUrl="/icons/list.svg"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </ul>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/views/SettingsView/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/views/SettingsView/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export * from "./SettingsView";
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user