redirecter for ao3 that adds opengraph metadata

update layout of generator form to be more compact

Changed files
+69 -56
src
app
generator
+60 -56
src/app/generator/page.js
···
<input type="text" name="url" id="url" onChange={e => setUrl(e.target.value)} />
</div>
<details><summary>Style Settings</summary>
-
<div className="input-field">
-
<label htmlFor="theme">Theme</label>
-
<select name="theme" id="theme" defaultValue={props.theme} onChange={e => updateProp("theme", e.target.value)}>
-
{Object.entries(themes).map((th, i) => {
-
return (
-
<option key={i} value={th[0]}>{th[1].name}</option>
-
)
-
})}
-
</select>
-
</div>
-
<div className="input-field">
-
<label htmlFor="baseFont">Base Font</label>
-
<select name="baseFont" id="baseFont" defaultValue={props.baseFont} onChange={e => updateProp("baseFont", e.target.value)}>
-
{Object.entries(baseFonts).sort().map((bf, i) => {
+
<div className="cols">
+
<div className="col">
+
<div className="input-field">
+
<label htmlFor="theme">Theme</label>
+
<select name="theme" id="theme" defaultValue={props.theme} onChange={e => updateProp("theme", e.target.value)}>
+
{Object.entries(themes).map((th, i) => {
+
return (
+
<option key={i} value={th[0]}>{th[1].name}</option>
+
)
+
})}
+
</select>
+
</div>
+
<div className="input-field">
+
<label htmlFor="baseFont">Base Font</label>
+
<select name="baseFont" id="baseFont" defaultValue={props.baseFont} onChange={e => updateProp("baseFont", e.target.value)}>
+
{Object.entries(baseFonts).sort().map((bf, i) => {
-
return (
-
<option key={i} value={bf[0]}>{bf[1].displayName}</option>
-
)
-
})}
-
</select>
-
</div>
-
<div className="input-field">
-
<label htmlFor="titleFont">Title Font</label>
-
<select name="titleFont" id="titleFont" defaultValue={props.titleFont} onChange={e => updateProp("titleFont", e.target.value)}>
-
{Object.entries({...titleFonts, ...baseFonts}).sort().map((tf, i) => {
-
return (
-
<option key={i} value={tf[0]}>{tf[1].displayName}</option>
-
)
-
})}
-
</select>
-
</div>
-
<div className="input-field">
-
<label htmlFor="features">Features:</label>
-
<ul>
-
<li><label><input type="checkbox" name="features[]" value="category" defaultChecked={props.category} onChange={e => updateProp(e.target.value, e.target.checked)} /> Category</label></li>
-
<li><label><input type="checkbox" name="features[]" value="rating" defaultChecked={props.rating} onChange={e => updateProp(e.target.value, e.target.checked)} /> Rating</label></li>
-
<li><label><input type="checkbox" name="features[]" value="warnings" defaultChecked={props.warnings} onChange={e => updateProp(e.target.value, e.target.checked)} /> Archive Warnings</label></li>
-
<li><label><input type="checkbox" name="features[]" value="charTags" defaultChecked={props.charTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Character Tags</label></li>
-
<li><label><input type="checkbox" name="features[]" value="relTags" defaultChecked={props.relTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Relationship Tags</label></li>
-
<li><label><input type="checkbox" name="features[]" value="freetags" defaultChecked={props.freeTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Free Tags</label></li>
-
<li><label><input type="checkbox" name="features[]" value="summary" defaultChecked={props.summary} onChange={e => updateProp(e.target.value, e.target.checked)} /> Summary</label></li>
-
<li><label><input type="checkbox" name="features[]" value="wordcount" defaultChecked={props.wordcount} onChange={e => updateProp(e.target.value, e.target.checked)} /> Wordcount</label></li>
-
<li><label><input type="checkbox" name="features[]" value="chapters" defaultChecked={props.chapters} onChange={e => updateProp(e.target.value, e.target.checked)} /> Chapters</label></li>
-
</ul>
-
</div>
-
<div className="input-field">
-
<label htmlFor="summaryOptions">Summary Type</label>
-
<ul>
-
<li><label><input type="radio" name="summaryType" value="basic" defaultChecked={props.summaryType === 'basic'} onChange={e => updateProp(e.target.name, e.target.value)} /> Story Summary</label></li>
-
<li><label><input type="radio" name="summaryType" defaultChecked={props.summaryType === 'chapter'} value="chapter" onChange={e => updateProp(e.target.name, e.target.value)} /> Chapter Summary (if available)</label></li>
-
<li><label><input type="radio" name="summaryType" defaultChecked={props.summaryType === 'custom'} value="custom" onChange={e => updateProp(e.target.name, e.target.value)} /> Custom Summary</label></li>
-
</ul>
-
</div>
-
{props.summaryType === 'custom' && (
+
return (
+
<option key={i} value={bf[0]}>{bf[1].displayName}</option>
+
)
+
})}
+
</select>
+
</div>
+
<div className="input-field">
+
<label htmlFor="titleFont">Title Font</label>
+
<select name="titleFont" id="titleFont" defaultValue={props.titleFont} onChange={e => updateProp("titleFont", e.target.value)}>
+
{Object.entries({...titleFonts, ...baseFonts}).sort().map((tf, i) => {
+
return (
+
<option key={i} value={tf[0]}>{tf[1].displayName}</option>
+
)
+
})}
+
</select>
+
</div>
+
</div>
<div className="input-field">
-
<label htmlFor="customSummary">Custom Summary</label>
-
<textarea name="customSummary" id="customSummary" onChange={e => updateProp(e.target.name, e.target.value)}></textarea>
+
<label htmlFor="features">Features:</label>
+
<ul>
+
<li><label><input type="checkbox" name="features[]" value="category" defaultChecked={props.category} onChange={e => updateProp(e.target.value, e.target.checked)} /> Category</label></li>
+
<li><label><input type="checkbox" name="features[]" value="rating" defaultChecked={props.rating} onChange={e => updateProp(e.target.value, e.target.checked)} /> Rating</label></li>
+
<li><label><input type="checkbox" name="features[]" value="warnings" defaultChecked={props.warnings} onChange={e => updateProp(e.target.value, e.target.checked)} /> Archive Warnings</label></li>
+
<li><label><input type="checkbox" name="features[]" value="charTags" defaultChecked={props.charTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Character Tags</label></li>
+
<li><label><input type="checkbox" name="features[]" value="relTags" defaultChecked={props.relTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Relationship Tags</label></li>
+
<li><label><input type="checkbox" name="features[]" value="freetags" defaultChecked={props.freeTags} onChange={e => updateProp(e.target.value, e.target.checked)} /> Free Tags</label></li>
+
<li><label><input type="checkbox" name="features[]" value="summary" defaultChecked={props.summary} onChange={e => updateProp(e.target.value, e.target.checked)} /> Summary</label></li>
+
<li><label><input type="checkbox" name="features[]" value="wordcount" defaultChecked={props.wordcount} onChange={e => updateProp(e.target.value, e.target.checked)} /> Wordcount</label></li>
+
<li><label><input type="checkbox" name="features[]" value="chapters" defaultChecked={props.chapters} onChange={e => updateProp(e.target.value, e.target.checked)} /> Chapters</label></li>
+
</ul>
+
</div>
+
<div className="input-field">
+
<label htmlFor="summaryOptions">Summary Type</label>
+
<ul>
+
<li><label><input type="radio" name="summaryType" value="basic" defaultChecked={props.summaryType === 'basic'} onChange={e => updateProp(e.target.name, e.target.value)} /> Story Summary</label></li>
+
<li><label><input type="radio" name="summaryType" defaultChecked={props.summaryType === 'chapter'} value="chapter" onChange={e => updateProp(e.target.name, e.target.value)} /> Chapter Summary (if available)</label></li>
+
<li><label><input type="radio" name="summaryType" defaultChecked={props.summaryType === 'custom'} value="custom" onChange={e => updateProp(e.target.name, e.target.value)} /> Custom Summary</label></li>
+
</ul>
+
{props.summaryType === 'custom' && (
+
<div className="input-field">
+
<label htmlFor="customSummary">Custom Summary</label>
+
<textarea name="customSummary" id="customSummary" onChange={e => updateProp(e.target.name, e.target.value)}></textarea>
+
</div>
+
)}
</div>
-
)}
+
</div>
</details>
</form>
{imgData && imgData !== '' && (
+9
src/app/globals.css
···
margin-bottom: 1em;
}
+
details .cols {
+
margin-top: 1em;
+
display: grid;
+
grid-template-columns: repeat(3, 1fr);
+
gap: 20px;
+
}
+
+
+
#output {
border: 1px white dashed;
}