Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 115 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import code, {
CustomHtmlOptions,
Custom404Options,
SubdomainRedirect,
RedirectRule,
} from "./code";
import "./styles.css";

Expand Down Expand Up @@ -171,6 +172,7 @@ export default function App() {
const [subdomainRedirects, setSubdomainRedirects] = useState<
SubdomainRedirect[]
>([]);
const [redirectRules, setRedirectRules] = useState<RedirectRule[]>([]);

function createInputHandler<T>(
setter: React.Dispatch<React.SetStateAction<T>>,
Expand Down Expand Up @@ -336,6 +338,29 @@ export default function App() {
setCopied(false);
}

function addRedirectRule(): void {
setRedirectRules([...redirectRules, { from: "", to: "", permanent: true }]);
setCopied(false);
}

function deleteRedirectRule(index: number): void {
setRedirectRules(redirectRules.filter((_, i) => i !== index));
setCopied(false);
}

function handleRedirectRuleChange(
index: number,
field: keyof RedirectRule,
value: string | boolean,
): void {
setRedirectRules(
redirectRules.map((rule, i) =>
i === index ? { ...rule, [field]: value } : rule,
),
);
setCopied(false);
}

function toggleSlugMetadata(index: number): void {
setSlugMetadataExpanded({
...slugMetadataExpanded,
Expand Down Expand Up @@ -403,6 +428,7 @@ export default function App() {
customHtml,
custom404,
subdomainRedirects,
redirectRules,
};

const script = noError ? code(codeData) : undefined;
Expand Down Expand Up @@ -1052,7 +1078,95 @@ export default function App() {
startIcon={<AddIcon />}
sx={{ mt: 1 }}
>
Add Redirect
Add Subdomain Redirect
</Button>
</Box>

<Box sx={{ mt: 3, pt: 2, borderTop: 1, borderColor: "grey.300" }}>
<Typography
variant="subtitle2"
color="text.secondary"
gutterBottom
>
URL Redirect Rules
</Typography>
<Typography variant="caption" color="text.secondary">
Redirect specific paths to other URLs (301 permanent / 302
temporary)
</Typography>
{redirectRules.map((rule, index) => (
<Box
key={index}
sx={{
mt: 1,
p: 1.5,
backgroundColor: "grey.100",
borderRadius: 1,
}}
>
<Stack direction="row" spacing={1} alignItems="flex-start">
<TextField
label="From Path"
placeholder="/old-page"
value={rule.from}
onChange={(e) =>
handleRedirectRuleChange(
index,
"from",
e.target.value,
)
}
variant="outlined"
size="small"
sx={{ flex: 1 }}
/>
<TextField
label="To Path/URL"
placeholder="/new-page or https://..."
value={rule.to}
onChange={(e) =>
handleRedirectRuleChange(index, "to", e.target.value)
}
variant="outlined"
size="small"
sx={{ flex: 2 }}
/>
<FormControlLabel
control={
<Switch
checked={rule.permanent}
onChange={(e) =>
handleRedirectRuleChange(
index,
"permanent",
e.target.checked,
)
}
size="small"
/>
}
label="301"
sx={{ minWidth: 70 }}
/>
<Button
onClick={() => deleteRedirectRule(index)}
color="error"
size="small"
sx={{ minWidth: "auto", px: 1 }}
>
<DeleteIcon fontSize="small" />
</Button>
</Stack>
</Box>
))}
<Button
onClick={addRedirectRule}
size="small"
variant="text"
startIcon={<AddIcon />}
sx={{ mt: 1 }}
>
Add Redirect Rule
</Button>
</Box>

Expand Down
33 changes: 33 additions & 0 deletions src/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export interface SubdomainRedirect {
redirectUrl: string;
}

export interface RedirectRule {
from: string;
to: string;
permanent: boolean;
}

export interface CodeData {
myDomain: string;
notionUrl: string;
Expand All @@ -69,6 +75,7 @@ export interface CodeData {
customHtml: CustomHtmlOptions;
custom404: Custom404Options;
subdomainRedirects: SubdomainRedirect[];
redirectRules: RedirectRule[];
}

function getId(url: string): string {
Expand Down Expand Up @@ -100,6 +107,7 @@ export default function code(data: CodeData): string {
customHtml,
custom404,
subdomainRedirects,
redirectRules,
} = data;
let url = myDomain.replace("https://", "").replace("http://", "");
if (url.slice(-1) === "/") url = url.slice(0, url.length - 1);
Expand Down Expand Up @@ -188,6 +196,21 @@ ${
.join("") || ""
} };

/*
* Step 3.8: custom redirect rules (optional)
* Redirect specific paths to other paths or external URLs (301/302)
*/
const REDIRECT_RULES = [
${
redirectRules
?.filter((r) => r.from && r.to)
.map(
(r) =>
` { from: '${r.from}', to: '${r.to}', permanent: ${r.permanent} },\n`,
)
.join("") || ""
} ];

/* Step 4: enter a Google Font name, you can choose from https://fonts.google.com */
const GOOGLE_FONT = '${googleFont || ""}';

Expand Down Expand Up @@ -323,6 +346,16 @@ ${
}
}

// Handle custom redirect rules (Issue #32)
for (const rule of REDIRECT_RULES) {
if (url.pathname === rule.from) {
const redirectUrl = rule.to.startsWith('http')
? rule.to
: 'https://' + MY_DOMAIN + rule.to;
return Response.redirect(redirectUrl, rule.permanent ? 301 : 302);
}
}

// Use the original Notion site domain instead of www.notion.so
url.hostname = NOTION_SITE_DOMAIN;
if (url.pathname === '/robots.txt') {
Expand Down
Loading