Fix wiki search overflowing on wide screens (#6047)

Confine the search menu to be at most the width of the page, or 80% of
the viewport width, whichever is smaller. To do this, introduce a new
`--container-width` variable for the descendant elements of
`.ui.container` to be able to access.

Also update the relevant e2e test: add a long 'lorem ipsum' page, add a
search for it, parameterize the width.
This commit is contained in:
Oto Šťáva 2024-11-24 16:41:09 +01:00
parent ad70e7dfb3
commit c0777279fe
No known key found for this signature in database
GPG key ID: 32B22D20C9B4E680
10 changed files with 65 additions and 25 deletions

View file

@ -86,7 +86,7 @@ func TestWiki(t *testing.T) {
Wiki(ctx) Wiki(ctx)
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
assert.EqualValues(t, "Home", ctx.Data["Title"]) assert.EqualValues(t, "Home", ctx.Data["Title"])
assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"]) assertPagesMetas(t, []string{"Home", "Long Page", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"])
} }
func TestWikiPages(t *testing.T) { func TestWikiPages(t *testing.T) {
@ -96,7 +96,7 @@ func TestWikiPages(t *testing.T) {
contexttest.LoadRepo(t, ctx, 1) contexttest.LoadRepo(t, ctx, 1)
WikiPages(ctx) WikiPages(ctx)
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status()) assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
assertPagesMetas(t, []string{"Home", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"]) assertPagesMetas(t, []string{"Home", "Long Page", "Page With Image", "Page With Spaced Name", "Unescaped File"}, ctx.Data["Pages"])
} }
func TestNewWiki(t *testing.T) { func TestNewWiki(t *testing.T) {

View file

@ -1,6 +1,6 @@
{{if .Results}} {{if .Results}}
{{range .Results}} {{range .Results}}
<a class="item tw-max-w-[80vw]" href="{{$.RepoLink}}/wiki/{{.Filename}}"> <a class="item tw-max-w-[min(80vw,var(--container-width))]" href="{{$.RepoLink}}/wiki/{{.Filename}}">
<b class="tw-block tw-mb-2 tw-whitespace-break-spaces">{{.Title}}</b> <b class="tw-block tw-mb-2 tw-whitespace-break-spaces">{{.Title}}</b>
{{range .LineCodes}} {{range .LineCodes}}
<p class="tw-my-0 tw-whitespace-break-spaces">{{.}}</p> <p class="tw-my-0 tw-whitespace-break-spaces">{{.}}</p>

View file

@ -6,17 +6,26 @@
import {expect} from '@playwright/test'; import {expect} from '@playwright/test';
import {test} from './utils_e2e.ts'; import {test} from './utils_e2e.ts';
test(`Search for long titles and test for no overflow`, async ({page}, workerInfo) => { for (const searchTerm of ['space', 'consectetur']) {
test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275'); for (const width of [null, 2560, 4000]) {
await page.goto('/user2/repo1/wiki'); test(`Search for '${searchTerm}' and test for no overflow ${width && `on ${width}-wide viewport` || ''}`, async ({page, viewport}, workerInfo) => {
await page.getByPlaceholder('Search wiki').fill('spaces'); test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275');
await page.getByPlaceholder('Search wiki').click();
// workaround: HTMX listens on keyup events, playwright's fill only triggers the input event await page.setViewportSize({
// so we manually "type" the last letter width: width ?? viewport.width,
await page.getByPlaceholder('Search wiki').dispatchEvent('keyup'); height: 1440, // We're testing that we fit horizontally - vertical scrolling is fine.
// timeout is necessary because HTMX search could be slow });
await expect(page.locator('#wiki-search a[href]')).toBeInViewport({ratio: 1}); await page.goto('/user2/repo1/wiki');
}); await page.getByPlaceholder('Search wiki').fill(searchTerm);
await page.getByPlaceholder('Search wiki').click();
// workaround: HTMX listens on keyup events, playwright's fill only triggers the input event
// so we manually "type" the last letter
await page.getByPlaceholder('Search wiki').dispatchEvent('keyup');
// timeout is necessary because HTMX search could be slow
await expect(page.locator('#wiki-search a[href]')).toBeInViewport({ratio: 1});
});
}
}
test(`Search results show titles (and not file names)`, async ({page}, workerInfo) => { test(`Search results show titles (and not file names)`, async ({page}, workerInfo) => {
test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275'); test.skip(workerInfo.project.name === 'Mobile Safari', 'Fails as always, see https://codeberg.org/forgejo/forgejo/pulls/5326#issuecomment-2313275');

View file

@ -0,0 +1 @@
xťŹÍn@…»ž§¸ű*ń†áGjŞŚmJ±‰C1“ě~R0ŹÓ§i}*ďU·•şĘ*gw>éHçËş¶­5<C2AD>6}§Ą€3”)Sh˛´0 9ÍTƨáž;2i2Óĺ®-É^óLň4wSžŰŞp™mSTČ­Ű\9V†Ô1Sép"Źşę¸ŐĽ|ůůëÇ“„ťî.Z>É법us™uíG 63<36>Ąđ)"9ÓóG­Ţ¶.÷ĺˇ.áâO¦ž¬ ň#XţJ$›ŘűË ¨?o<1˝_Š)n<>/±~ćá6ąëŐcS­űl<ÔXŽiŇb3{@ź÷B,g±řĎ ” Ż‘ŰËK|˝ĆEĐ[ß0\ď<>ÉŹaWńݢRć|¤ři{şąžxd… ŤĂÉßô9<ĐŮŇŹšg>»¨Š KOvÉ"D§J„sEŕęŘśzňĎĆ[Í_s!2ϡév%ěe©Čo(˝”

View file

@ -1 +1 @@
0dca5bd9b5d7ef937710e056f575e86c0184ba85 d49ac742d44063dcf69d4e0afe725813b777dd89

View file

@ -133,8 +133,31 @@ func TestAPIListWikiPages(t *testing.T) {
}, },
}, },
{ {
Title: "Page With Image", Title: "Long Page",
HTMLURL: meta[1].HTMLURL, HTMLURL: meta[1].HTMLURL,
SubURL: "Long-Page",
LastCommit: &api.WikiCommit{
ID: "d49ac742d44063dcf69d4e0afe725813b777dd89",
Author: &api.CommitUser{
Identity: api.Identity{
Name: "Oto Šťáva",
Email: "oto.stava@gmail.com",
},
Date: "2024-11-23T11:16:51Z",
},
Committer: &api.CommitUser{
Identity: api.Identity{
Name: "Oto Šťáva",
Email: "oto.stava@gmail.com",
},
Date: "2024-11-23T11:16:51Z",
},
Message: "add long page\n",
},
},
{
Title: "Page With Image",
HTMLURL: meta[2].HTMLURL,
SubURL: "Page-With-Image", SubURL: "Page-With-Image",
LastCommit: &api.WikiCommit{ LastCommit: &api.WikiCommit{
ID: "0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3", ID: "0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3",
@ -157,7 +180,7 @@ func TestAPIListWikiPages(t *testing.T) {
}, },
{ {
Title: "Page With Spaced Name", Title: "Page With Spaced Name",
HTMLURL: meta[2].HTMLURL, HTMLURL: meta[3].HTMLURL,
SubURL: "Page-With-Spaced-Name", SubURL: "Page-With-Spaced-Name",
LastCommit: &api.WikiCommit{ LastCommit: &api.WikiCommit{
ID: "c10d10b7e655b3dab1f53176db57c8219a5488d6", ID: "c10d10b7e655b3dab1f53176db57c8219a5488d6",
@ -180,7 +203,7 @@ func TestAPIListWikiPages(t *testing.T) {
}, },
{ {
Title: "Unescaped File", Title: "Unescaped File",
HTMLURL: meta[3].HTMLURL, HTMLURL: meta[4].HTMLURL,
SubURL: "Unescaped-File", SubURL: "Unescaped-File",
LastCommit: &api.WikiCommit{ LastCommit: &api.WikiCommit{
ID: "0dca5bd9b5d7ef937710e056f575e86c0184ba85", ID: "0dca5bd9b5d7ef937710e056f575e86c0184ba85",

View file

@ -3,12 +3,14 @@
.ui.container { .ui.container {
display: block; display: block;
max-width: 100%; --container-width: 100%;
max-width: var(--container-width);
} }
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.ui.ui.ui.container:not(.fluid) { .ui.ui.ui.container:not(.fluid) {
width: auto; --container-width: auto;
width: var(--container-width);
margin-left: 1em; margin-left: 1em;
margin-right: 1em; margin-right: 1em;
} }
@ -16,7 +18,8 @@
@media (min-width: 768px) and (max-width: 991.98px) { @media (min-width: 768px) and (max-width: 991.98px) {
.ui.ui.ui.container:not(.fluid) { .ui.ui.ui.container:not(.fluid) {
width: 723px; --container-width: 723px;
width: var(--container-width);
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
@ -24,7 +27,8 @@
@media (min-width: 992px) and (max-width: 1199.98px) { @media (min-width: 992px) and (max-width: 1199.98px) {
.ui.ui.ui.container:not(.fluid) { .ui.ui.ui.container:not(.fluid) {
width: 933px; --container-width: 933px;
width: var(--container-width);
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
@ -32,14 +36,16 @@
@media (min-width: 1200px) { @media (min-width: 1200px) {
.ui.ui.ui.container:not(.fluid) { .ui.ui.ui.container:not(.fluid) {
width: 1127px; --container-width: 1127px;
width: var(--container-width);
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
} }
.ui.fluid.container { .ui.fluid.container {
width: 100%; --container-width: 100%;
width: var(--container-width);
} }
.ui[class*="center aligned"].container { .ui[class*="center aligned"].container {
@ -48,7 +54,8 @@
/* overwrite width of containers inside the main page content div (div with class "page-content") */ /* overwrite width of containers inside the main page content div (div with class "page-content") */
.page-content .ui.ui.ui.container:not(.fluid) { .page-content .ui.ui.ui.container:not(.fluid) {
width: 1280px; --container-width: 1280px;
width: var(--container-width);
max-width: calc(100% - calc(2 * var(--page-margin-x))); max-width: calc(100% - calc(2 * var(--page-margin-x)));
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;