Skip to content

Instantly share code, notes, and snippets.

@oezguerisbert
Created January 19, 2024 14:27
Show Gist options
  • Select an option

  • Save oezguerisbert/ebe88c9225e0d1eacca52804e437785d to your computer and use it in GitHub Desktop.

Select an option

Save oezguerisbert/ebe88c9225e0d1eacca52804e437785d to your computer and use it in GitHub Desktop.
TailwindCSS Issue with Solid-Start / Vinxi
// @refresh reload
import { Router } from "@solidjs/router";
import { Suspense, createEffect, createSignal, onCleanup } from "solid-js";
import { Providers } from "./components/providers";
import { FileRoutes } from "@solidjs/start";
import "./root.css";
export default function App() {
const [colorMode, setColorMode] = createSignal<"dark" | "light">("dark");
const toggleColorMode = async () => {
const cm = colorMode() === "light" ? "dark" : "light";
setColorMode(cm);
const html = document.querySelector("html");
if (html) {
html.classList.toggle("dark");
}
// store color mode in local storage
window.localStorage.setItem("colorMode", cm);
};
createEffect(() => {
const cm = (window.localStorage.getItem("colorMode") as "dark" | "light" | null) ?? "dark";
if (cm) {
setColorMode(cm);
}
const handler = async (e: KeyboardEvent) => {
if (e.ctrlKey && e.key === "b") {
e.preventDefault();
await toggleColorMode();
}
};
document.addEventListener("keydown", handler);
onCleanup(() => {
document.removeEventListener("keydown", handler);
});
});
return (
<Router
root={(props) => (
<>
<Suspense>
<Providers>{props.children}</Providers>
</Suspense>
</>
)}
>
<FileRoutes />
</Router>
);
}
import { A, redirect, useParams } from "@solidjs/router";
import { createQuery } from "@tanstack/solid-query";
import { createEffect } from "solid-js";
import Md from "~/components/Markdown";
import { Queries } from "~/utils/api/queries";
export default function BlogIdPage() {
const { id } = useParams();
if (!id) return redirect("/notfound", { status: 404 });
const blog = createQuery(() => ({
queryKey: ["blog", id],
queryFn: () => Queries.blog(id),
}));
createEffect(() => {
if (!blog.isSuccess) return;
document.title = blog.data?.title + " | Blog | Oetzi.dev";
});
return (
<main class="flex container mx-auto flex-col gap-10 py-10">
<div class="flex flex-row items-center justify-between">
<div>
<h1 class="text-4xl font-bold select-none">{blog.isSuccess && blog.data ? blog.data.title : "Loading..."}</h1>
</div>
<A
href="./configure"
class="bg-black dark:bg-white text-white dark:text-black rounded-md px-2 py-1 font-medium w-max"
>
Edit
</A>
</div>
<Md>{blog.isSuccess && blog.data ? blog.data.content : "Loading..."}</Md>
</main>
);
}
import { mount, StartClient } from "@solidjs/start/client";
mount(() => <StartClient />, document.getElementById("app"));
import { createHandler } from "@solidjs/start/entry";
import { StartServer } from "@solidjs/start/server";
export default createHandler((event) => (
<StartServer
document={({ assets, children, scripts }) => (
<html lang="en" classList={{ dark: true }}>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
{assets}
</head>
<body class="bg-white dark:bg-black text-black dark:text-white">
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
));
import { A } from "@solidjs/router";
import { createQuery } from "@tanstack/solid-query";
import { For, Show, createEffect } from "solid-js";
import { PublicBlog } from "~/components/PublicBlog";
import { PublicProject } from "~/components/PublicProject";
import { Queries } from "~/utils/api/queries";
import { Session } from "~/utils/api/session";
export default function Home() {
const projects = createQuery(() => ({
queryKey: ["projects"],
queryFn: () => Queries.projects(),
staleTime: Infinity,
}));
const blogs = createQuery(() => ({
queryKey: ["blogs"],
queryFn: () => Queries.blogs(),
staleTime: Infinity,
}));
createEffect(() => {
document.title = "Home | Oetzi.dev";
});
return (
<main class="flex container mx-auto flex-col gap-10 py-10">
<div class="w-full flex flex-col gap-10 py-4">
<div class="w-full flex flex-row gap-2 items-center justify-between">
<h1 class="text-4xl font-bold select-none">Blogs</h1>
<div class="flex flex-row gap-2 items-center">
<Show when={Session.isLoggedIn()}>
<A
href="/blog/create"
class="bg-black dark:bg-white text-white dark:text-black text-sm rounded-sm px-2 py-1 font-medium"
>
Create Blog
</A>
</Show>
</div>
</div>
<div class="flex flex-col gap-4">
<For
each={blogs.isSuccess && blogs.data}
fallback={
<div class="col-span-full flex flex-col items-start justify-center rounded-sm p-10 gap-8 border border-neutral-300 dark:border-neutral-800">
<h3 class="text-xl font-bold">No blogs found.</h3>
<p class="text-md font-medium">I currently have no blogs published.</p>
</div>
}
>
{(blog) => <PublicBlog blog={blog} />}
</For>
</div>
</div>
<div class="w-full flex flex-col gap-10 py-4">
<div class="w-full flex flex-row gap-2 items-center justify-between">
<h1 class="text-4xl font-bold select-none">Projects</h1>
<div class="flex flex-row gap-2 items-center">
<Show when={Session.isLoggedIn()}>
<A
href="/project/create"
class="bg-black dark:bg-white text-white dark:text-black text-sm rounded-sm px-2 py-1 font-medium"
>
Create Project
</A>
</Show>
</div>
</div>
<div class="flex flex-col gap-4">
<For
each={projects.isSuccess && projects.data}
fallback={
<div class="col-span-full flex flex-col items-start justify-center rounded-sm p-10 gap-8 border border-neutral-300 dark:border-neutral-800">
<h3 class="text-xl font-bold">No projects found.</h3>
<p class="text-md font-medium">I currently have no projects published.</p>
</div>
}
>
{(project) => <PublicProject project={project} />}
</For>
</div>
</div>
</main>
);
}
import { action } from "@solidjs/router";
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query";
import { Match, Switch } from "solid-js";
import { Session } from "../../utils/api/session";
const queryClient = new QueryClient();
export const Providers = (props: { children: any }) => {
const logoutAction = action(Session.logout);
const loggedIn = Session.isLoggedIn();
return (
<>
<QueryClientProvider client={queryClient}>
<nav class="flex flex-row items-center justify-between flex-wrap bg-white dark:bg-black border-b border-neutral-300 dark:border-neutral-900 w-screen py-2">
<div class="container mx-auto flex flex-row items-center justify-between flex-wrap py-2">
<a href="/" class="hover:underline">
oetzi.dev
</a>
<Switch>
<Match when={loggedIn}>
<form action={logoutAction} method="post">
<button
class="bg-black dark:bg-white text-white dark:text-black text-sm rounded-sm px-2 py-1 font-medium"
type="submit"
>
Logout
</button>
</form>
</Match>
<Match when={!loggedIn}>
<a
href={import.meta.env.VITE_AUTH_URL}
class="bg-black dark:bg-white text-white dark:text-black text-sm rounded-sm px-2 py-1 font-medium"
>
Login
</a>
</Match>
</Switch>
</div>
</nav>
{props.children}
</QueryClientProvider>
</>
);
};
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { For, JSX, Match, Show, Switch } from "solid-js";
import Markdown from "solid-marked/component";
import { Blogs } from "../utils/api/blog";
import { A, action } from "@solidjs/router";
import { Session } from "../utils/api/session";
import { Blog } from "@oetzidev/core/entities/blogs";
import { Dynamic } from "solid-js/web";
import { cn } from "../utils/cn";
import Mdd from "./Markdown";
dayjs.extend(relativeTime);
type PublicBlogProps = {
blog: Blog.Frontend;
};
export const PublicBlog = (props: PublicBlogProps) => {
return (
<div class="flex flex-col text-black dark:text-white border border-neutral-300 dark:border-neutral-800 overflow-clip">
<div class="flex flex-row items-center justify-between p-4 pb-2">
<div class="w-full flex flex-row items-center justify-between gap-2.5">
<A href={`/blog/${props.blog.id}`} class="text-xl font-bold hover:underline ">
{props.blog.title}
</A>
<div class="flex flex-row items-center gap-2.5">
<Show when={Session.isLoggedIn()}>
<A
href={`/blog/${props.blog.id}/configure`}
class="flex flex-row gap-2.5 p-2 border border-neutral-300 dark:border-neutral-800 rounded-md"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 20h9" />
<path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z" />
</svg>
</A>
<form action={Blogs.remove} method="post">
<input type="hidden" name="id" value={props.blog.id} />
<button type="submit" class="flex flex-row gap-2.5 text-rose-500 p-2 border border-rose-500 rounded-md">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 6h18" />
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" />
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" />
<line x1="10" x2="10" y1="11" y2="17" />
<line x1="14" x2="14" y1="11" y2="17" />
</svg>
</button>
</form>
</Show>
</div>
</div>
<div class="flex flex-row items-center gap-2.5"></div>
</div>
<div class="flex flex-row items-center justify-between p-4 pt-2">
<div class="flex flex-row items-center gap-2.5">
<p class="text-sm text-neutral-500 dark:text-neutral-400">{dayjs(props.blog.createdAt).fromNow()}</p>
</div>
<div class="flex flex-row items-center gap-2.5">
<div class="flex flex-row items-center gap-2.5">
<p class="text-sm text-neutral-500 dark:text-neutral-400">{props.blog.visibility}</p>
</div>
</div>
</div>
<div class="flex flex-col gap-2 p-4 max-h-40">
<Mdd>{props.blog.content}</Mdd>
</div>
</div>
);
};
@tailwind base;
@tailwind components;
@tailwind utilities;
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,js,jsx,ts,tsx}"],
theme: {
extend: {},
},
darkMode: "class",
plugins: [
// default prefix is "ui"
require("@kobalte/tailwindcss"),
require("@tailwindcss/typography"),
],
};
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({
ssr: {
noExternal: ["@kobalte/core", "@internationalized/message"],
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment