language selector, but not quite workinhg yet
This commit is contained in:
parent
36bcf7277c
commit
e7701f4b7d
|
@ -4,7 +4,7 @@ Easily create EPUB e-book files with proper RTL support.
|
|||
|
||||
This is a web app that uses [pandoc](https://pandoc.org) to create .epub files for e-books in RTL languages. Making RTL e-books can be tricky. This tries app tries to simplify the process as much as possible, so that anyone can make them.
|
||||
|
||||
[Try it live - RTL EPUB Maker](https://rtl-epub-maker.lingdocs.com)
|
||||
### [Try it live - RTL EPUB Maker 📚](https://rtl-epub-maker.lingdocs.com)
|
||||
|
||||
## Running
|
||||
|
||||
|
@ -39,7 +39,7 @@ If you are using `linux/amd64` architecture you can just run the [the docker ima
|
|||
docker compose up
|
||||
```
|
||||
|
||||
If you are using an architecture other than `linux/amd64` you will need to build your own Docker image.
|
||||
If you are using an architecture other than `linux/amd64` you will need to build your own docker image.
|
||||
|
||||
```sh
|
||||
docker build . -t rtl-epub-maker
|
||||
|
@ -52,4 +52,4 @@ The app will be served on `http://localhost:3001`. Add a reverse proxy with SSL
|
|||
|
||||
---
|
||||
|
||||
Code is licensed under a [MIT License](https://github.com/lingdocs/rtl-epub-maker/blob/master/LICENSE). Contributions are welcome.
|
||||
Code is licensed under an [MIT License](https://github.com/lingdocs/rtl-epub-maker/blob/master/LICENSE). Contributions are welcome.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ChangeEvent, useState, useRef } from "react";
|
||||
import Select from "react-select";
|
||||
import LanguageSelect from "./LanguageSelect";
|
||||
|
||||
const requiredFields = [
|
||||
"title",
|
||||
|
@ -20,8 +21,7 @@ type Option = {
|
|||
label: string,
|
||||
};
|
||||
|
||||
const baseSettings = {
|
||||
language: "ps-AF",
|
||||
const baseSettings = {
|
||||
dir: "rtl",
|
||||
"page-progression-direction": "rtl",
|
||||
};
|
||||
|
@ -55,6 +55,21 @@ function BookInfoInput({ handleSubmit }: { handleSubmit: (info: { frontmatter: F
|
|||
[name]: value,
|
||||
}));
|
||||
}
|
||||
function handleLanguageChange(lang: string | null) {
|
||||
setState(s => {
|
||||
if (!lang) {
|
||||
delete s.lang;
|
||||
delete s.language;
|
||||
return s
|
||||
}
|
||||
return {
|
||||
...s,
|
||||
// TODO: using both, but which is proper/necessary?
|
||||
lang,
|
||||
language: lang,
|
||||
};
|
||||
});
|
||||
}
|
||||
function submit() {
|
||||
const cover = coverRef.current.files[0] as (File | undefined);
|
||||
handleSubmit({
|
||||
|
@ -65,24 +80,24 @@ function BookInfoInput({ handleSubmit }: { handleSubmit: (info: { frontmatter: F
|
|||
cover,
|
||||
});
|
||||
}
|
||||
console.log(state);
|
||||
console.log("will render");
|
||||
return <div style={{ maxWidth: "500px" }}>
|
||||
<div className="my-3">
|
||||
<label htmlFor="cover-file" className="form-label">cover image <span className="text-muted">(.jpg or .png less than 5mb)</span></label>
|
||||
<input multiple={false} ref={coverRef} className="form-control" type="file" id="cover-file" accept="image/jpeg,image/png"/>
|
||||
</div>
|
||||
{fields.map((field) => (
|
||||
<div key={field} className="d-flex flex-row align-items-end mb-2">
|
||||
<div className="col-auto" style={{ width: "100%" }}>
|
||||
<label htmlFor={field} className="form-label d-flex flex-row align-items-center">
|
||||
{!requiredFields.includes(field) && <span className="me-2">
|
||||
<button type="button" className="btn btn-sm btn-outline-secondary" onClick={() => handleRemoveField(field)}>
|
||||
X
|
||||
</button>
|
||||
</span>}
|
||||
<span>{field}</span>
|
||||
</label>
|
||||
<input onChange={handleFieldChange} type="text" className="form-control" id={field} name={field} value={state[field]} />
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<label htmlFor={field} className="form-label d-flex flex-row align-items-center">
|
||||
{!requiredFields.includes(field) && <span className="me-2">
|
||||
<button type="button" className="btn btn-sm btn-outline-secondary" onClick={() => handleRemoveField(field)}>
|
||||
X
|
||||
</button>
|
||||
</span>}
|
||||
<span>{field}</span>
|
||||
</label>
|
||||
<input onChange={handleFieldChange} type="text" className="form-control" id={field} name={field} value={state[field]} />
|
||||
</div>
|
||||
))}
|
||||
<div className="mt-4 mb-2">add fields:</div>
|
||||
|
@ -97,6 +112,7 @@ function BookInfoInput({ handleSubmit }: { handleSubmit: (info: { frontmatter: F
|
|||
// @ts-ignore
|
||||
options={availableFieldsOptions}
|
||||
/>
|
||||
<LanguageSelect value={state.lang} onChange={handleLanguageChange} />
|
||||
<button onClick={submit} type="button" className="btn btn-primary my-4">Create .epub</button>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import Select from "react-select";
|
||||
import { useState } from "react";
|
||||
|
||||
const languageOptions = [
|
||||
{ value: "ar", label: "Arabic" },
|
||||
{ value: "fa", label: "Farsi" },
|
||||
{ value: "prs", label: "Dari" },
|
||||
{ value: "ps", label: "Pashto" },
|
||||
{ value: "ps-AF", label: "Pashto (Afghanistan) "},
|
||||
{ value: "ps-PK", label: "Pashto (Pakistan) "},
|
||||
{ value: "ur", label: "Urdu" },
|
||||
{ value: "other", label: "Other..." },
|
||||
];
|
||||
|
||||
function LanguageSelect({ value, onChange }: {
|
||||
value: string | null,
|
||||
onChange: (language: string | null) => void,
|
||||
}) {
|
||||
const [showingOther, setShowingOther] = useState<boolean>(false);
|
||||
function handleChange(o: { value: string, label: string }) {
|
||||
if (!o) {
|
||||
onChange(null);
|
||||
} else if (o.value === "other") {
|
||||
setShowingOther(true);
|
||||
onChange(null);
|
||||
} else {
|
||||
if (showingOther) setShowingOther(false);
|
||||
onChange(o.value);
|
||||
}
|
||||
}
|
||||
return <div>
|
||||
<div className="mt-4 mb-2">language:</div>
|
||||
<Select
|
||||
className="basic-single"
|
||||
classNamePrefix="select"
|
||||
isClearable={true}
|
||||
value={typeof value === "number" ? null : languageOptions.find(o => value === o.value)}
|
||||
isSearchable
|
||||
// @ts-ignore
|
||||
onChange={handleChange}
|
||||
// @ts-ignore
|
||||
options={languageOptions}
|
||||
/>
|
||||
{showingOther && <div className="my-2">
|
||||
<label htmlFor="otherLang" className="form-label d-flex flex-row align-items-center">
|
||||
<span>Custom <a href="https://www.w3.org/International/articles/language-tags/" target="_blank">IETF BCP 47</a> Language Code</span>
|
||||
</label>
|
||||
{/* TODO: for some reason can't use value={value} with this - but it still works */}
|
||||
<input onChange={(e) => onChange(e.target.value)} type="text" className="form-control" id="otherLang" />
|
||||
</div>}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default LanguageSelect;
|
Loading…
Reference in New Issue