handré laubscher
Writing desk · Loading
handré laubscher
Writing desk
No account? Create one
Pin this post to the top of the grid
Publishing
Date shown to readers
Leave empty to publish immediately
Engagement targets
How quickly activity builds up
Featured image
Click or drop image here
Uploads to Supabase storage
Options
Readers can comment without an account or name
Content blocks
Insert interactive elements into your post at the cursor position.
All published writing
Create production-quality quote images
Click or drop photo
Preview — 2× export is double resolution
Manage author profiles & post as them
Personas
Loading…
Select a comment to reply to, or leave as top-level
Click or drop photo
Autonomous view & like accumulation — invisible to readers
Each tick adds views/likes across selected posts
Random amount between min and max each tick
Fire a single large burst on selected posts immediately.
Loading posts…
Activity log
No activity yet…
Subscribers, newsletter, and mailing list
Total
0
Post alerts
0
Newsletter
0
Compose newsletter
Member list
Click refresh to load.
Homepage, sign in & sign up header photos
Upload new images below. Changes go live on the site immediately. Recommended formats: JPG/WebP. Max 8 MB per file.
The wide header image at the top of the homepage. Ideal ratio: 16:9 or wider. Current:
Click or drop to upload new banner
Your portrait used in the About section. Square or portrait orientation works best. Current:
Click or drop to upload new profile photo
The left-panel photo shown on both the sign in and sign up pages. Portrait or landscape, tall crop. Current:
Click or drop to upload new auth header
Images are stored in your Supabase Storage bucket site-images. Make sure this bucket exists and has public read access. URLs are saved to the site_settings table.
Connection & account
Set your display name and profile picture. This is used when you post comments as yourself on the blog.
Click or drop photo
Project: mqgutltvdwqhmkjgzyqs.supabase.co
Run this SQL in the Supabase SQL editor to set up all required tables.
-- blog_posts
create table if not exists blog_posts (
id bigserial primary key,
title text not null,
subtitle text,
category text,
excerpt text,
content text,
featured_image_url text,
reading_time int default 5,
featured boolean default false,
view_cap int default 5000,
like_cap int default 200,
growth_speed float default 1.0,
allow_anonymous_comments boolean default false,
scheduled_at timestamptz,
published_at timestamptz default now(),
created_at timestamptz default now()
);
-- Migration: add allow_anonymous_comments if table already exists
alter table blog_posts add column if not exists allow_anonymous_comments boolean default false;
-- post_stats
create table if not exists post_stats (
id bigserial primary key,
post_id text not null unique,
views int default 0,
likes int default 0,
last_grown timestamptz default now()
);
-- comments (with threading + avatars)
create table if not exists comments (
id bigserial primary key,
post_id text not null,
parent_id bigint references comments(id),
author_name text not null,
author_email text,
avatar_url text,
body text not null,
created_at timestamptz default now()
);
-- personas
create table if not exists poll_votes (
id bigserial primary key,
poll_id text not null,
post_id text not null,
option_index int not null,
voter_id text not null,
created_at timestamptz default now(),
unique(poll_id, voter_id)
);
alter table poll_votes enable row level security;
create policy "Public read poll votes" on poll_votes for select using (true);
create policy "Public insert poll votes" on poll_votes for insert with check (true);
-- personas
create table if not exists personas (
id bigserial primary key,
name text not null,
bio text,
avatar_url text,
created_at timestamptz default now()
);
-- user_profiles (public readers)
create table if not exists user_profiles (
id text primary key,
display_name text,
avatar_url text,
bio text,
subscribe_new_posts boolean default false,
subscribe_newsletter boolean default false,
created_at timestamptz default now()
);
-- Migration: add subscription columns if table already exists
alter table user_profiles add column if not exists subscribe_new_posts boolean default false;
alter table user_profiles add column if not exists subscribe_newsletter boolean default false;
-- RLS
alter table blog_posts enable row level security;
alter table post_stats enable row level security;
alter table comments enable row level security;
alter table personas enable row level security;
alter table user_profiles enable row level security;
-- Public read
create policy "Public read posts" on blog_posts for select using (true);
create policy "Public read stats" on post_stats for select using (true);
create policy "Public read comments" on comments for select using (true);
create policy "Public read personas" on personas for select using (true);
create policy "Public read profiles" on user_profiles for select using (true);
-- Public write
create policy "Public insert stats" on post_stats for insert with check (true);
create policy "Public update stats" on post_stats for update using (true);
create policy "Public insert comments" on comments for insert with check (true);
-- Auth write
create policy "Auth manage posts" on blog_posts for all using (auth.role()='authenticated');
create policy "Auth manage personas" on personas for all using (auth.role()='authenticated');
create policy "Self manage profile" on user_profiles for all using (auth.uid()::text = id);
-- Storage bucket
-- insert into storage.buckets (id, name, public) values ('blog-images', 'blog-images', true);
Signed in as: —