Skip to content

Commit

Permalink
Allow titleless homepage
Browse files Browse the repository at this point in the history
This removes the default homepage title and adds the
options to name the page directly, use a block name
or show no name at all. That last option is only allowed
for homepages.
  • Loading branch information
owi92 committed Nov 29, 2024
1 parent fe23b4e commit a600f0f
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 34 deletions.
19 changes: 13 additions & 6 deletions backend/src/api/model/realm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,24 @@ impl_from_db!(

impl Realm {
pub(crate) async fn root(context: &Context) -> ApiResult<Self> {
let (selection, mapping) = select!(child_order, moderator_roles, admin_roles);
let (selection, mapping) = select!(
child_order,
moderator_roles,
admin_roles,
name,
name_from_block,
resolved_name: "realms.resolved_name",
);
let row = context.db
.query_one(&format!("select {selection} from realms where id = 0"), &[])
.await?;

Ok(Self {
key: Key(0),
parent_key: None,
plain_name: None,
resolved_name: None,
name_from_block: None,
plain_name: mapping.name.of(&row),
resolved_name: mapping.resolved_name.of(&row),
name_from_block: mapping.name_from_block.of(&row),
path_segment: String::new(),
full_path: String::new(),
index: 0,
Expand Down Expand Up @@ -322,8 +329,8 @@ impl Realm {
}

/// The raw information about the name of the realm, showing where the name
/// is coming from and if there is no name, why that is. Is `null` for the
/// root realm, non-null for all other realms.
/// is coming from and if there is no name, why that is. Can be `null` only for the
/// root realm, must be non-null for all other realms.
fn name_source(&self) -> Option<RealmNameSource> {
if let Some(name) = &self.plain_name {
Some(RealmNameSource::Plain(PlainRealmName {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/api/model/realm/mutations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ impl Realm {
realm.require_moderator_rights(context)?;

let db = &context.db;
if name.plain.is_some() == name.block.is_some() {
if !realm.is_main_root() && name.plain.is_some() == name.block.is_some() {
return Err(invalid_input!("exactly one of name.block and name.plain has to be set"));
}
let block = name.block
Expand Down
1 change: 1 addition & 0 deletions backend/src/db/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,5 @@ static MIGRATIONS: Lazy<BTreeMap<u64, Migration>> = include_migrations![
36: "playlist-blocks",
37: "redo-search-triggers-and-listed",
38: "event-texts",
39: "realm-names-constraint-revision",
];
10 changes: 10 additions & 0 deletions backend/src/db/migrations/39-realm-names-constraint-revision.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- Adjusts name_source constraint to allow custom names for root, including null.

alter table realms
drop constraint valid_name_source,
add constraint valid_name_source check (
-- Root is allowed to have no name.
(id = 0 and name is null or name_from_block is null)
-- All other realms have either a plain or derived name.
or (id <> 0 and (name is null) != (name_from_block is null))
);
1 change: 1 addition & 0 deletions frontend/src/i18n/locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ manage:
name-from-block-description: >
Video/Serie-Element von dieser Seite verknüpfen, sodass der Seitenname
immer dem Titel des verknüpften Elements entspricht.
no-name: Keinen Namen anzeigen
no-blocks: Auf dieser Seite befinden sich keine verknüpfbaren Videos/Serien.
rename-failed: Änderung des Namen fehlgeschlagen.
no-rename-root: >
Expand Down
1 change: 1 addition & 0 deletions frontend/src/i18n/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ manage:
name-from-block: Derive name from video or series
name-from-block-description: >
Link a video/series-element from this page: the page name will always be the title of the linked element.
no-name: Omit name
no-blocks: There are no linkable video/series on this page.
rename-failed: Failed to change the name.
no-rename-root: >
Expand Down
11 changes: 4 additions & 7 deletions frontend/src/routes/Realm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import { RootLoader } from "../layout/Root";
import { NotFound } from "./NotFound";
import { Nav } from "../layout/Navigation";
import { LinkList, LinkWithIcon } from "../ui";
import CONFIG from "../config";
import { characterClass, useTitle, useTranslatedConfig } from "../util";
import { characterClass, useTitle } from "../util";
import { makeRoute } from "../rauta";
import { MissingRealmName } from "./util";
import { realmBreadcrumbs } from "../util/realm";
Expand Down Expand Up @@ -143,17 +142,15 @@ type Props = {

const RealmPage: React.FC<Props> = ({ realm }) => {
const { t } = useTranslation();
const siteTitle = useTranslatedConfig(CONFIG.siteTitle);
const breadcrumbs = realmBreadcrumbs(t, realm.ancestors);

const title = realm.isMainRoot ? siteTitle : realm.name;
useTitle(title, realm.isMainRoot);
useTitle(realm.name);

return <>
{!realm.isMainRoot && (
<Breadcrumbs path={breadcrumbs} tail={realm.name ?? <MissingRealmName />} />
)}
{title && (
{realm.name && (
<div css={{
marginBottom: 20,
display: "flex",
Expand All @@ -162,7 +159,7 @@ const RealmPage: React.FC<Props> = ({ realm }) => {
columnGap: 12,
rowGap: 6,
}}>
<h1 css={{ display: "inline-block", marginBottom: 0 }}>{title}</h1>
<h1 css={{ display: "inline-block", marginBottom: 0 }}>{realm.name}</h1>
{realm.isUserRealm && <UserRealmNote realm={realm} />}
</div>
)}
Expand Down
36 changes: 19 additions & 17 deletions frontend/src/routes/manage/Realm/General.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,46 +60,40 @@ type Props = {
};

export const General: React.FC<Props> = ({ fragRef }) => {
const { t } = useTranslation();
const realm = useFragment(fragment, fragRef);

// We do not allow changing the name of the root realm.
if (realm.isMainRoot) {
return <p>{t("manage.realm.general.no-rename-root")}</p>;
}

const { nameSource, ...rest } = realm;
if (nameSource == null) {
if (!realm.isMainRoot && nameSource == null) {
return bug("name source is null for non-root realm");
}

return <NameForm realm={{ nameSource, ...rest }} />;
};

type NameFormProps = {
realm: GeneralRealmData$data & {
nameSource: NonNullable<GeneralRealmData$data["nameSource"]>;
};
realm: GeneralRealmData$data;
};

export const NameForm: React.FC<NameFormProps> = ({ realm }) => {
type FormData = {
name: string | null;
block: string | null;
nameSource: "plain-name" | "name-from-block";
nameSource: "plain-name" | "name-from-block" | "no-name";
};

const initial = {
name: realm.nameSource.__typename === "PlainRealmName"
name: realm.nameSource?.__typename === "PlainRealmName"
? realm.name
: null,
block: realm.nameSource.__typename === "RealmNameFromBlock"
block: realm.nameSource?.__typename === "RealmNameFromBlock"
// TODO: this breaks when we add new block types
? realm.nameSource.block.id ?? null
: null,
nameSource: realm.nameSource.__typename === "PlainRealmName"
? "plain-name"
: "name-from-block",
nameSource: !realm.nameSource ? "no-name" : (
realm.nameSource.__typename === "PlainRealmName"
? "plain-name"
: "name-from-block"
),
} as const;

const { t } = useTranslation();
Expand Down Expand Up @@ -135,9 +129,11 @@ export const NameForm: React.FC<NameFormProps> = ({ realm }) => {
const block = watch("block");
const nameSource = watch("nameSource");
const isPlain = nameSource === "plain-name";
const fromBlock = nameSource === "name-from-block";
const canSave = match(nameSource, {
"name-from-block": () => block != null && block !== initial.block,
"plain-name": () => !!name && name !== initial.name,
"no-name": () => initial.nameSource !== "no-name",
});

const suitableBlocks = realm.blocks
Expand Down Expand Up @@ -223,7 +219,7 @@ export const NameForm: React.FC<NameFormProps> = ({ realm }) => {
</div>
</div>
</label>
{!isPlain && <div>
{fromBlock && <div>
{suitableBlocks.length === 0 && <div>
<Card kind="error">{t("manage.realm.general.no-blocks")}</Card>
</div>}
Expand All @@ -239,6 +235,12 @@ export const NameForm: React.FC<NameFormProps> = ({ realm }) => {
</Select>}
</div>}
</div>
{realm.isMainRoot && <div>
<label>
<input type="radio" value="no-name" {...register("nameSource")} />
{t("manage.realm.general.no-name")}
</label>
</div>}
</div>

<div css={{ display: "flex", alignItems: "center" }}>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,8 @@ type Realm implements Node {
name: String
"""
The raw information about the name of the realm, showing where the name
is coming from and if there is no name, why that is. Is `null` for the
root realm, non-null for all other realms.
is coming from and if there is no name, why that is. Can be `null` only for the
root realm, must be non-null for all other realms.
"""
nameSource: RealmNameSource
"Returns `true` if this is the root of the public realm tree (with path = \"/\")."
Expand Down
2 changes: 1 addition & 1 deletion util/dummy-realms.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# A realm tree definition for development. Can be imported with
# `cargo run -- import-realm-tree dummy-realms.yaml`

name: ""
name: "Tobira Videoportal"
path: ""
blocks:
- text: |
Expand Down

0 comments on commit a600f0f

Please sign in to comment.