Some fixes
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 5s
This commit is contained in:
parent
ed7cf8a254
commit
58e67fede3
1
hindki/drizzle/0001_luxuriant_iceman.sql
Normal file
1
hindki/drizzle/0001_luxuriant_iceman.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "words" ALTER COLUMN "type" SET NOT NULL;
|
||||||
287
hindki/drizzle/meta/0001_snapshot.json
Normal file
287
hindki/drizzle/meta/0001_snapshot.json
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
{
|
||||||
|
"id": "318667f9-2cec-43d4-9e1c-9c6ddedb8664",
|
||||||
|
"prevId": "e5ed4824-2e96-4821-84c9-c33bd5d1cda8",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.examples": {
|
||||||
|
"name": "examples",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"word_id": {
|
||||||
|
"name": "word_id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"hindi": {
|
||||||
|
"name": "hindi",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"english": {
|
||||||
|
"name": "english",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"name": "note",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"examples_word_id_words_id_fk": {
|
||||||
|
"name": "examples_word_id_words_id_fk",
|
||||||
|
"tableFrom": "examples",
|
||||||
|
"tableTo": "words",
|
||||||
|
"columnsFrom": [
|
||||||
|
"word_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.see_also": {
|
||||||
|
"name": "see_also",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"word_id": {
|
||||||
|
"name": "word_id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"reference": {
|
||||||
|
"name": "reference",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"name": "note",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"see_also_word_id_words_id_fk": {
|
||||||
|
"name": "see_also_word_id_words_id_fk",
|
||||||
|
"tableFrom": "see_also",
|
||||||
|
"tableTo": "words",
|
||||||
|
"columnsFrom": [
|
||||||
|
"word_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.tags": {
|
||||||
|
"name": "tags",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"tags_name_unique": {
|
||||||
|
"name": "tags_name_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.word_tags": {
|
||||||
|
"name": "word_tags",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"word_id": {
|
||||||
|
"name": "word_id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"tag_id": {
|
||||||
|
"name": "tag_id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"word_tags_word_id_words_id_fk": {
|
||||||
|
"name": "word_tags_word_id_words_id_fk",
|
||||||
|
"tableFrom": "word_tags",
|
||||||
|
"tableTo": "words",
|
||||||
|
"columnsFrom": [
|
||||||
|
"word_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"word_tags_tag_id_tags_id_fk": {
|
||||||
|
"name": "word_tags_tag_id_tags_id_fk",
|
||||||
|
"tableFrom": "word_tags",
|
||||||
|
"tableTo": "tags",
|
||||||
|
"columnsFrom": [
|
||||||
|
"tag_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.words": {
|
||||||
|
"name": "words",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"hindi": {
|
||||||
|
"name": "hindi",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"english": {
|
||||||
|
"name": "english",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"gender": {
|
||||||
|
"name": "gender",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"name": "note",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"updated_at": {
|
||||||
|
"name": "updated_at",
|
||||||
|
"type": "timestamp",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,6 +8,13 @@
|
|||||||
"when": 1759431829568,
|
"when": 1759431829568,
|
||||||
"tag": "0000_bouncy_demogoblin",
|
"tag": "0000_bouncy_demogoblin",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1759452792993,
|
||||||
|
"tag": "0001_luxuriant_iceman",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -256,15 +256,12 @@ export default function AddVocabForm() {
|
|||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onClick={() => setShowNewTag(!showNewTag)}>
|
|
||||||
{showNewTag ? 'Cancel' : 'New Category'}
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showNewTag && (
|
{showNewTag && (
|
||||||
<>
|
<>
|
||||||
<div className="form-group">
|
<div className="form-group new-word">
|
||||||
<label htmlFor="newTagName">Tag Name:</label>
|
<label htmlFor="newTagName">Name:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
id="newTagName"
|
id="newTagName"
|
||||||
@ -274,18 +271,21 @@ export default function AddVocabForm() {
|
|||||||
required={showNewTag}
|
required={showNewTag}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div className="form-group new-word">
|
||||||
<label htmlFor="newTagDescription">Tag Description:</label>
|
<label htmlFor="newTagDescription">Description:</label>
|
||||||
<input
|
<textarea
|
||||||
type="text"
|
|
||||||
id="newTagDescription"
|
id="newTagDescription"
|
||||||
value={newTagDescription}
|
value={newTagDescription}
|
||||||
onChange={(e) => setNewTagDescription(e.target.value)}
|
onChange={(e) => setNewTagDescription(e.target.value)}
|
||||||
|
rows={3}
|
||||||
placeholder="e.g., Words related to food and beverages"
|
placeholder="e.g., Words related to food and beverages"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
<button type="button" onClick={() => setShowNewTag(!showNewTag)}>
|
||||||
|
{showNewTag ? 'Cancel' : 'New Category'}
|
||||||
|
</button>
|
||||||
<h3>New Word</h3>
|
<h3>New Word</h3>
|
||||||
<div className="form-group new-word">
|
<div className="form-group new-word">
|
||||||
<label htmlFor="english">English:</label>
|
<label htmlFor="english">English:</label>
|
||||||
@ -315,8 +315,18 @@ export default function AddVocabForm() {
|
|||||||
<label htmlFor="type">Type:</label>
|
<label htmlFor="type">Type:</label>
|
||||||
<select
|
<select
|
||||||
id="type"
|
id="type"
|
||||||
value={formData.type}
|
value={['noun', 'verb', 'adjective', 'adverb', 'pronoun', 'conjunction', 'preposition', 'interjection'].includes(formData.type) ? formData.type : 'custom'}
|
||||||
onChange={(e) => setFormData({ ...formData, type: e.target.value })}
|
onChange={(e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
if (value === 'custom') {
|
||||||
|
const customValue = prompt('Enter custom type:', formData.type);
|
||||||
|
if (customValue) {
|
||||||
|
setFormData({ ...formData, type: customValue });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setFormData({ ...formData, type: value });
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<option value="noun">Noun</option>
|
<option value="noun">Noun</option>
|
||||||
<option value="verb">Verb</option>
|
<option value="verb">Verb</option>
|
||||||
@ -326,10 +336,11 @@ export default function AddVocabForm() {
|
|||||||
<option value="conjunction">Conjunction</option>
|
<option value="conjunction">Conjunction</option>
|
||||||
<option value="preposition">Preposition</option>
|
<option value="preposition">Preposition</option>
|
||||||
<option value="interjection">Interjection</option>
|
<option value="interjection">Interjection</option>
|
||||||
|
<option value="custom">{['noun', 'verb', 'adjective', 'adverb', 'pronoun', 'conjunction', 'preposition', 'interjection'].includes(formData.type) ? 'Custom...' : `Custom: ${formData.type}`}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={`form-group new-word ${formData.type !== 'noun' ? 'hidden' : ''}`}>
|
<div className="form-group new-word">
|
||||||
<label htmlFor="gender">Gender:</label>
|
<label htmlFor="gender">Gender:</label>
|
||||||
<select
|
<select
|
||||||
id="gender"
|
id="gender"
|
||||||
|
|||||||
@ -1,21 +1,15 @@
|
|||||||
---
|
---
|
||||||
|
// @ts-ignore
|
||||||
import Default from "@astrojs/starlight/components/PageSidebar.astro";
|
import Default from "@astrojs/starlight/components/PageSidebar.astro";
|
||||||
|
// @ts-ignore
|
||||||
import MobileTableOfContents from "@astrojs/starlight/components/MobileTableOfContents.astro";
|
import MobileTableOfContents from "@astrojs/starlight/components/MobileTableOfContents.astro";
|
||||||
import { Icon } from "@astrojs/starlight/components";
|
|
||||||
const isLearningPage = Astro.locals.starlightRoute.id === "learn";
|
const isLearningPage = Astro.locals.starlightRoute.id === "learn";
|
||||||
|
|
||||||
import { getCollection } from "astro:content";
|
import { storage } from "@/lib/storage";
|
||||||
|
|
||||||
const categories = await getCollection("vocabList");
|
const categories = await storage.getAllTags();
|
||||||
const typesSet = new Set<string>();
|
const types = await storage.getAllTypes();
|
||||||
categories.forEach((category) => {
|
const words = await storage.getAllWords();
|
||||||
category.data.words.forEach((word) => {
|
|
||||||
if (word.type) {
|
|
||||||
typesSet.add(word.type);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const types = Array.from(typesSet).sort();
|
|
||||||
---
|
---
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -33,12 +27,12 @@ const types = Array.from(typesSet).sort();
|
|||||||
<input
|
<input
|
||||||
data-filter="category"
|
data-filter="category"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={category.id}
|
id={category.name}
|
||||||
name={category.id}
|
name={category.name}
|
||||||
value={category.id}
|
value={category.id}
|
||||||
checked
|
checked
|
||||||
/>
|
/>
|
||||||
<label for={category.id}>{category.id}</label>
|
<label for={category.name}>{category.name}</label>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -50,9 +44,9 @@ const types = Array.from(typesSet).sort();
|
|||||||
<input
|
<input
|
||||||
data-filter="type"
|
data-filter="type"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={type}
|
id={type.toString()}
|
||||||
name={type}
|
name={type.toString()}
|
||||||
value={type}
|
value={type.toString()}
|
||||||
checked
|
checked
|
||||||
/>
|
/>
|
||||||
<label for={type}>{type}</label>
|
<label for={type}>{type}</label>
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
import Default from "@astrojs/starlight/components/Sidebar.astro";
|
import Default from "@astrojs/starlight/components/Sidebar.astro";
|
||||||
import SidebarPersister from "@astrojs/starlight/components/SidebarPersister.astro";
|
import SidebarPersister from "@astrojs/starlight/components/SidebarPersister.astro";
|
||||||
import SidebarSublist from "@astrojs/starlight/components/SidebarSublist.astro";
|
import SidebarSublist from "@astrojs/starlight/components/SidebarSublist.astro";
|
||||||
|
// @ts-ignore
|
||||||
import MobileMenuFooter from "virtual:starlight/components/MobileMenuFooter";
|
import MobileMenuFooter from "virtual:starlight/components/MobileMenuFooter";
|
||||||
import { storage } from "../lib/storage";
|
import { storage } from "../lib/storage";
|
||||||
import { titlecase } from "@/lib/utils";
|
import { titlecase } from "@/lib/utils";
|
||||||
@ -10,11 +11,11 @@ const tags = await storage.getAllTags();
|
|||||||
|
|
||||||
const { sidebar: astroSidebar } = Astro.locals.starlightRoute;
|
const { sidebar: astroSidebar } = Astro.locals.starlightRoute;
|
||||||
const tagsFromApi = {
|
const tagsFromApi = {
|
||||||
type: "group",
|
type: "group" as const,
|
||||||
label: "Vocabulary",
|
label: "Vocabulary",
|
||||||
badge: undefined,
|
badge: undefined,
|
||||||
entries: tags.map((tag) => ({
|
entries: tags.map((tag) => ({
|
||||||
type: "link",
|
type: "link" as const,
|
||||||
label: titlecase(tag.name),
|
label: titlecase(tag.name),
|
||||||
href: `/vocabulary/${tag.name}`,
|
href: `/vocabulary/${tag.name}`,
|
||||||
isCurrent: Astro.url.pathname === `/vocabulary/${tag.name}`,
|
isCurrent: Astro.url.pathname === `/vocabulary/${tag.name}`,
|
||||||
@ -24,7 +25,7 @@ const tagsFromApi = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Replace vocabulary with tags fetched from api
|
// Replace vocabulary with tags fetched from api
|
||||||
const sidebar = astroSidebar.map((item) => {
|
const sidebar = astroSidebar.map((item: any) => {
|
||||||
if (item.label === "Vocabulary") {
|
if (item.label === "Vocabulary") {
|
||||||
return tagsFromApi;
|
return tagsFromApi;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export const words = pgTable('words', {
|
|||||||
id: serial('id').primaryKey(),
|
id: serial('id').primaryKey(),
|
||||||
hindi: text('hindi').notNull(),
|
hindi: text('hindi').notNull(),
|
||||||
english: text('english').notNull(),
|
english: text('english').notNull(),
|
||||||
type: text('type'), // noun, verb, adjective, etc.
|
type: text('type').notNull(), // noun, verb, adjective, etc.
|
||||||
gender: text('gender'), // m, f, or null
|
gender: text('gender'), // m, f, or null
|
||||||
note: text('note'),
|
note: text('note'),
|
||||||
createdAt: timestamp('created_at').notNull().defaultNow(),
|
createdAt: timestamp('created_at').notNull().defaultNow(),
|
||||||
|
|||||||
@ -103,7 +103,7 @@ class PGStorage {
|
|||||||
return await db.query.tags.findMany();
|
return await db.query.tags.findMany();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllTypes(): Promise<String[]> {
|
async getAllTypes(): Promise<string[]> {
|
||||||
const types = new Set<string>();
|
const types = new Set<string>();
|
||||||
const allWords = await this.getAllWords();
|
const allWords = await this.getAllWords();
|
||||||
allWords.forEach((word) => {
|
allWords.forEach((word) => {
|
||||||
@ -118,7 +118,7 @@ class PGStorage {
|
|||||||
.values({
|
.values({
|
||||||
hindi: newWord.hindi,
|
hindi: newWord.hindi,
|
||||||
english: newWord.english,
|
english: newWord.english,
|
||||||
type: newWord.type || null,
|
type: newWord.type,
|
||||||
gender: newWord.gender || null,
|
gender: newWord.gender || null,
|
||||||
note: newWord.note || null,
|
note: newWord.note || null,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,6 +7,13 @@ import markdownItMark from "markdown-it-mark";
|
|||||||
import { storage } from "@/lib/storage";
|
import { storage } from "@/lib/storage";
|
||||||
import { titlecase } from "@/lib/utils";
|
import { titlecase } from "@/lib/utils";
|
||||||
|
|
||||||
|
function typeToTitle(type: string | null | undefined) {
|
||||||
|
if (!type) return "";
|
||||||
|
const partsOfSpeech = ["noun", "verb", "adjective", "adverb"];
|
||||||
|
const maybePlural = partsOfSpeech.includes(type.toLowerCase()) ? "s" : "";
|
||||||
|
return titlecase(type!) + maybePlural;
|
||||||
|
}
|
||||||
|
|
||||||
const md = markdownit().use(markdownItMark);
|
const md = markdownit().use(markdownItMark);
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
@ -28,7 +35,7 @@ const words = await storage.getWordsByTag(tag);
|
|||||||
|
|
||||||
const wordtypes = [...new Set(words.map((word) => word.type).filter(Boolean))];
|
const wordtypes = [...new Set(words.map((word) => word.type).filter(Boolean))];
|
||||||
const wordsByType = wordtypes.map((type) => ({
|
const wordsByType = wordtypes.map((type) => ({
|
||||||
type: titlecase(type!) + "s",
|
type: typeToTitle(type),
|
||||||
words: words.filter((word) => word.type === type),
|
words: words.filter((word) => word.type === type),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -37,7 +44,7 @@ const headings = wordsByType.flatMap(({ type, words }) => {
|
|||||||
{
|
{
|
||||||
text: type,
|
text: type,
|
||||||
depth: 2,
|
depth: 2,
|
||||||
slug: type.toLowerCase().replace(/\s+/g, "-"),
|
slug: type!.toLowerCase().replace(/\s+/g, "-"),
|
||||||
},
|
},
|
||||||
].concat(
|
].concat(
|
||||||
words.map((word) => ({
|
words.map((word) => ({
|
||||||
@ -61,7 +68,7 @@ const headings = wordsByType.flatMap(({ type, words }) => {
|
|||||||
{
|
{
|
||||||
wordsByType.map(({ type, words }) => (
|
wordsByType.map(({ type, words }) => (
|
||||||
<div class="word-type-section">
|
<div class="word-type-section">
|
||||||
<AnchorHeading level="3" id={type}>
|
<AnchorHeading level="3" id={type!}>
|
||||||
{type}
|
{type}
|
||||||
</AnchorHeading>
|
</AnchorHeading>
|
||||||
<ul class="part-of-speech-list">
|
<ul class="part-of-speech-list">
|
||||||
|
|||||||
@ -6,7 +6,7 @@ export interface Word {
|
|||||||
id: number;
|
id: number;
|
||||||
english: string;
|
english: string;
|
||||||
hindi: string;
|
hindi: string;
|
||||||
type?: string | null;
|
type: string;
|
||||||
gender?: "m" | "f" | null;
|
gender?: "m" | "f" | null;
|
||||||
note?: string | null;
|
note?: string | null;
|
||||||
examples?: Example[];
|
examples?: Example[];
|
||||||
@ -38,7 +38,7 @@ export interface SeeAlso {
|
|||||||
export interface NewWord {
|
export interface NewWord {
|
||||||
hindi: string;
|
hindi: string;
|
||||||
english: string;
|
english: string;
|
||||||
type?: string;
|
type: string;
|
||||||
gender?: "m" | "f";
|
gender?: "m" | "f";
|
||||||
note?: string;
|
note?: string;
|
||||||
examples?: NewExample[];
|
examples?: NewExample[];
|
||||||
@ -87,7 +87,7 @@ export const wordSchema = z.object({
|
|||||||
id: z.number(),
|
id: z.number(),
|
||||||
english: z.string(),
|
english: z.string(),
|
||||||
hindi: z.string(),
|
hindi: z.string(),
|
||||||
type: z.string().optional().nullable(),
|
type: z.string(),
|
||||||
gender: z.enum(["m", "f"]).optional().nullable(),
|
gender: z.enum(["m", "f"]).optional().nullable(),
|
||||||
note: z.string().optional().nullable(),
|
note: z.string().optional().nullable(),
|
||||||
examples: z.array(exampleSchema).optional(),
|
examples: z.array(exampleSchema).optional(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user