- Written {new Date(p().date).toDateString()}
-
+ {/* Content that slides over the fixed image */}
+
+
+
+
+
+ Written {new Date(p().date).toDateString()}
+
+ By Michael Freno
+
+
+
-
-
- {(tag) => (
-
-
{tag.value}
+
+
+
+ {postData.comments.length}{" "}
+ {postData.comments.length === 1
+ ? "Comment"
+ : "Comments"}
+
+
+
-
- {/* Post body */}
-
-
-
-
-
-
- {/* Comments section */}
-
diff --git a/src/routes/contact.tsx b/src/routes/contact.tsx
index 23f5545..e345772 100644
--- a/src/routes/contact.tsx
+++ b/src/routes/contact.tsx
@@ -215,6 +215,7 @@ export default function ContactPage() {
name="name"
value={user()?.displayName ?? ""}
placeholder=" "
+ title="Please enter your name"
class="underlinedInput w-full bg-transparent"
/>
@@ -227,6 +228,7 @@ export default function ContactPage() {
name="email"
value={user()?.email ?? ""}
placeholder=" "
+ title="Please enter a valid email address"
class="underlinedInput w-full bg-transparent"
/>
@@ -239,6 +241,7 @@ export default function ContactPage() {
required
name="message"
placeholder=" "
+ title="Please enter your message"
class="underlinedInput w-full bg-transparent"
rows={4}
/>
diff --git a/src/routes/login/index.tsx b/src/routes/login/index.tsx
index 80af48a..cb49224 100644
--- a/src/routes/login/index.tsx
+++ b/src/routes/login/index.tsx
@@ -38,11 +38,13 @@ export default function LoginPage() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
+ // Derive state directly from URL parameters (no signals needed)
+ const register = () => searchParams.mode === "register";
+ const usePassword = () => searchParams.auth === "password";
+
// State management
- const [register, setRegister] = createSignal(false);
const [error, setError] = createSignal("");
const [loading, setLoading] = createSignal(false);
- const [usePassword, setUsePassword] = createSignal(false);
const [countDown, setCountDown] = createSignal(0);
const [emailSent, setEmailSent] = createSignal(false);
const [showPasswordError, setShowPasswordError] = createSignal(false);
@@ -370,29 +372,23 @@ export default function LoginPage() {
fallback={
Already have an account?
-
+
}
>
Don't have an account yet?
-
+
@@ -406,6 +402,7 @@ export default function LoginPage() {
required
ref={emailRef}
placeholder=" "
+ title="Please enter a valid email address"
class="underlinedInput bg-transparent"
/>
@@ -425,6 +422,7 @@ export default function LoginPage() {
onInput={register() ? handleNewPasswordChange : undefined}
onBlur={register() ? handlePasswordBlur : undefined}
placeholder=" "
+ title="Password must be at least 8 characters"
class="underlinedInput bg-transparent"
/>
@@ -478,6 +476,7 @@ export default function LoginPage() {
ref={passwordConfRef}
onInput={handlePasswordConfChange}
placeholder=" "
+ title="Password must be at least 8 characters and match the password above"
class="underlinedInput bg-transparent"
/>
@@ -584,22 +583,20 @@ export default function LoginPage() {
{/* Toggle password/email link */}
-
+
-
+
diff --git a/src/routes/login/request-password-reset.tsx b/src/routes/login/request-password-reset.tsx
index 612f6a0..571fce5 100644
--- a/src/routes/login/request-password-reset.tsx
+++ b/src/routes/login/request-password-reset.tsx
@@ -144,6 +144,7 @@ export default function RequestPasswordResetPage() {
required
disabled={loading()}
placeholder=" "
+ title="Please enter a valid email address"
class="underlinedInput w-full bg-transparent"
/>
diff --git a/src/server/conditional-parser.ts b/src/server/conditional-parser.ts
index 110cf01..3a4d29a 100644
--- a/src/server/conditional-parser.ts
+++ b/src/server/conditional-parser.ts
@@ -63,27 +63,37 @@ function processBlockConditionals(
html: string,
context: ConditionalContext
): string {
- // Regex to match conditional blocks
- // Matches:
...
- const conditionalRegex =
- /
]*class="[^"]*conditional-block[^"]*"[^>]*data-condition-type="([^"]+)"[^>]*data-condition-value="([^"]+)"[^>]*data-show-when="(true|false)"[^>]*>([\s\S]*?)<\/div>/gi;
+ // More flexible regex that handles attributes in any order
+ // Match div with class="conditional-block" and capture the full tag
+ const divRegex =
+ /
]*class="[^"]*conditional-block[^"]*"[^>]*)>([\s\S]*?)<\/div>/gi;
let processedHtml = html;
let match: RegExpExecArray | null;
// Reset regex lastIndex
- conditionalRegex.lastIndex = 0;
+ divRegex.lastIndex = 0;
// Collect all matches first to avoid regex state issues
const matches: ConditionalBlock[] = [];
- while ((match = conditionalRegex.exec(html)) !== null) {
- matches.push({
- fullMatch: match[0],
- conditionType: match[1],
- conditionValue: match[2],
- showWhen: match[3],
- content: match[4]
- });
+ while ((match = divRegex.exec(html)) !== null) {
+ const attributes = match[1];
+ const content = match[2];
+
+ // Extract individual attributes
+ const typeMatch = /data-condition-type="([^"]+)"/.exec(attributes);
+ const valueMatch = /data-condition-value="([^"]+)"/.exec(attributes);
+ const showWhenMatch = /data-show-when="(true|false)"/.exec(attributes);
+
+ if (typeMatch && valueMatch && showWhenMatch) {
+ matches.push({
+ fullMatch: match[0],
+ conditionType: typeMatch[1],
+ conditionValue: valueMatch[1],
+ showWhen: showWhenMatch[1],
+ content: content
+ });
+ }
}
// Process each conditional block
@@ -120,27 +130,37 @@ function processInlineConditionals(
html: string,
context: ConditionalContext
): string {
- // Regex to match inline conditionals
- // Matches: ...
- const inlineRegex =
- /]*class="[^"]*conditional-inline[^"]*"[^>]*data-condition-type="([^"]+)"[^>]*data-condition-value="([^"]+)"[^>]*data-show-when="(true|false)"[^>]*>([\s\S]*?)<\/span>/gi;
+ // More flexible regex that handles attributes in any order
+ // Match span with class="conditional-inline" and capture the full tag
+ const spanRegex =
+ /]*class="[^"]*conditional-inline[^"]*"[^>]*)>([\s\S]*?)<\/span>/gi;
let processedHtml = html;
let match: RegExpExecArray | null;
// Reset regex lastIndex
- inlineRegex.lastIndex = 0;
+ spanRegex.lastIndex = 0;
// Collect all matches first
const matches: ConditionalBlock[] = [];
- while ((match = inlineRegex.exec(html)) !== null) {
- matches.push({
- fullMatch: match[0],
- conditionType: match[1],
- conditionValue: match[2],
- showWhen: match[3],
- content: match[4]
- });
+ while ((match = spanRegex.exec(html)) !== null) {
+ const attributes = match[1];
+ const content = match[2];
+
+ // Extract individual attributes
+ const typeMatch = /data-condition-type="([^"]+)"/.exec(attributes);
+ const valueMatch = /data-condition-value="([^"]+)"/.exec(attributes);
+ const showWhenMatch = /data-show-when="(true|false)"/.exec(attributes);
+
+ if (typeMatch && valueMatch && showWhenMatch) {
+ matches.push({
+ fullMatch: match[0],
+ conditionType: typeMatch[1],
+ conditionValue: valueMatch[1],
+ showWhen: showWhenMatch[1],
+ content: content
+ });
+ }
}
// Process each inline conditional