Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add safe search filter for NSFW rooms #208

Merged
merged 16 commits into from
May 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 67 additions & 18 deletions client/css/room-directory.css
Original file line number Diff line number Diff line change
Expand Up @@ -237,24 +237,22 @@
color: #abb5be;
}

.RoomDirectoryView_roomList {
display: grid;
gap: 20px;
.RoomDirectoryView_mainContentSection {
width: 100%;
max-width: 1180px;
padding-left: 20px;
padding-right: 20px;
margin-top: 20px;
margin-top: 15px;
margin-bottom: 0;
}

.RoomDirectoryView_roomList {
display: grid;
gap: 20px;
}

.RoomDirectoryView_roomListError {
display: block;
width: 100%;
max-width: 1180px;
padding-left: 20px;
padding-right: 20px;
margin-top: 20px;

line-height: 1.5;
}
Expand All @@ -269,17 +267,14 @@
}

@media (min-width: 750px) {
.RoomDirectoryView_roomList {
grid-template-columns: repeat(2, 1fr);
margin-top: 40px;
.RoomDirectoryView_mainContentSection {
margin-top: 30px;
padding-left: 40px;
padding-right: 40px;
}

.RoomDirectoryView_roomListError {
margin-top: 40px;
padding-left: 40px;
padding-right: 40px;
.RoomDirectoryView_roomList {
grid-template-columns: repeat(2, 1fr);
}
}

Expand All @@ -289,6 +284,40 @@
}
}

.RoomDirectoryView_safeSearchToggleSection {
display: flex;
justify-content: flex-end;
}

.RoomDirectoryView_safeSearchToggle {
display: flex;
align-items: center;
}

.RoomDirectoryView_safeSearchToggleLabel {
padding-left: 0.3em;
}

.RoomDirectoryView_safeSearchToggleCheckbox {
appearance: none;

position: relative;
width: 20px;
height: 10px;

background-color: #ffffff;
border: 2px solid rgba(200, 200, 200, 1);
box-shadow: inset -10px 0px 0px 0px rgba(200, 200, 200, 1);
border-radius: 10px;

transition: all 0.2s ease;
}

.RoomDirectoryView_safeSearchToggleCheckbox:checked {
border: 2px solid #2774c2;
box-shadow: inset 10px 0px 0px 0px #2774c2;
}

.RoomCardView {
overflow: hidden;
display: flex;
Expand All @@ -301,6 +330,10 @@
border-radius: 8px;
}

.RoomCardView.blockedBySafeSearch {
background-color: #d0d9e1;
}

.RoomCardView_header {
display: flex;
align-items: top;
Expand Down Expand Up @@ -350,6 +383,14 @@
text-overflow: ellipsis;
}

.RoomCardView_blockedBySafeSearchTopic {
margin-top: 8px;
margin-bottom: 8px;

line-height: 1.2em;
font-style: italic;
}

.RoomCardView_footer {
display: flex;
/**
Expand Down Expand Up @@ -398,14 +439,22 @@
cursor: pointer;
}

.RoomCardView_viewButton[disabled] {
border-color: #2774c299;

color: #2774c299;

cursor: auto;
}

@media (max-width: 750px) {
.RoomCardView_viewButton {
padding: 8px 32px;
}
}

.RoomCardView_viewButtonWrapperLink:hover > .RoomCardView_viewButton,
.RoomCardView_viewButtonWrapperLink:focus > .RoomCardView_viewButton {
.RoomCardView_viewButtonWrapperLink:hover > .RoomCardView_viewButton:not([disabled]),
.RoomCardView_viewButtonWrapperLink:focus > .RoomCardView_viewButton:not([disabled]) {
background-color: #2774c2;
color: #ffffff;
}
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"dompurify": "^2.3.9",
"escape-string-regexp": "^4.0.0",
"express": "^4.17.2",
"hydrogen-view-sdk": "npm:@mlm/hydrogen-view-sdk@^0.26.0-scratch",
"hydrogen-view-sdk": "npm:@mlm/hydrogen-view-sdk@^0.27.0-scratch",
"json5": "^2.2.1",
"linkedom": "^0.14.17",
"matrix-public-archive-shared": "file:./shared/",
Expand Down
29 changes: 29 additions & 0 deletions shared/lib/local-storage-keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const assert = require('./assert');

const LOCAL_STORAGE_KEYS = {
addedHomeservers: 'addedHomeservers',
safeSearchEnabled: 'safeSearchEnabled',
debugActiveDateIntersectionObserver: 'debugActiveDateIntersectionObserver',
};

// Just make sure they match for sanity. All we really care about is that they are
// unique amongst each other.
Object.keys(LOCAL_STORAGE_KEYS).every((key) => {
const value = LOCAL_STORAGE_KEYS[key];
const doesKeyMatchValue = key === value;
assert(
doesKeyMatchValue,
`LOCAL_STORAGE_KEYS should have keys that are the same as their values for sanity but saw ${key}=${value}.`
);
});

// Make sure all of the keys/values are unique
assert(
new Set(Object.values(LOCAL_STORAGE_KEYS)).length !== Object.values(LOCAL_STORAGE_KEYS).length,
'Duplicate values in LOCAL_STORAGE_KEYS. They should be unique otherwise ' +
'there will be collisions and LocalStorage will be overwritten.'
);

module.exports = LOCAL_STORAGE_KEYS;
1 change: 1 addition & 0 deletions shared/room-directory-vm-render-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ async function mountHydrogen() {
urlRouter: urlRouter,
history: archiveHistory,
// Our options
basePath: config.basePath,
homeserverUrl: config.matrixServerUrl,
homeserverName: config.matrixServerName,
matrixPublicArchiveURLCreator,
Expand Down
2 changes: 1 addition & 1 deletion shared/viewmodels/AvatarViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class AvatarViewModel extends ViewModel {

const { homeserverUrlToPullMediaFrom, avatarUrl, avatarTitle, avatarLetterString, entityId } =
options;
assert(homeserverUrlToPullMediaFrom);
assert(!avatarUrl || homeserverUrlToPullMediaFrom);
assert(avatarTitle);
assert(avatarLetterString);
assert(entityId);
Expand Down
11 changes: 6 additions & 5 deletions shared/viewmodels/DeveloperOptionsContentViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

const { ViewModel } = require('hydrogen-view-sdk');

const DEBUG_ACTIVE_DATE_INTERSECTION_OBSERVER_LOCAL_STORAGE_KEY =
'debugActiveDateIntersectionObserver';
const LOCAL_STORAGE_KEYS = require('matrix-public-archive-shared/lib/local-storage-keys');

class DeveloperOptionsContentViewModel extends ViewModel {
constructor(options) {
Expand All @@ -17,11 +16,13 @@ class DeveloperOptionsContentViewModel extends ViewModel {
loadValuesFromPersistence() {
if (window.localStorage) {
this._debugActiveDateIntersectionObserver = JSON.parse(
window.localStorage.getItem(DEBUG_ACTIVE_DATE_INTERSECTION_OBSERVER_LOCAL_STORAGE_KEY)
window.localStorage.getItem(LOCAL_STORAGE_KEYS.debugActiveDateIntersectionObserver)
);
this.emitChange('debugActiveDateIntersectionObserver');
} else {
console.warn(`Skipping read from LocalStorage since LocalStorage not available`);
console.warn(
`Skipping \`${LOCAL_STORAGE_KEYS.debugActiveDateIntersectionObserver}\` read from LocalStorage since LocalStorage is not available`
);
}
}

Expand All @@ -32,7 +33,7 @@ class DeveloperOptionsContentViewModel extends ViewModel {
toggleDebugActiveDateIntersectionObserver(checkedValue) {
this._debugActiveDateIntersectionObserver = checkedValue;
window.localStorage.setItem(
DEBUG_ACTIVE_DATE_INTERSECTION_OBSERVER_LOCAL_STORAGE_KEY,
LOCAL_STORAGE_KEYS.debugActiveDateIntersectionObserver,
this._debugActiveDateIntersectionObserver
);
this.emitChange('debugActiveDateIntersectionObserver');
Expand Down
82 changes: 82 additions & 0 deletions shared/viewmodels/RoomCardViewModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
'use strict';

const { ViewModel } = require('hydrogen-view-sdk');

const assert = require('matrix-public-archive-shared/lib/assert');
const MatrixPublicArchiveURLCreator = require('matrix-public-archive-shared/lib/url-creator');

class RoomCardViewModel extends ViewModel {
constructor(options) {
super(options);
const { room, basePath, homeserverUrlToPullMediaFrom, viaServers } = options;
assert(room);
assert(basePath);
assert(homeserverUrlToPullMediaFrom);
assert(viaServers);

this._matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator(basePath);

this._roomId = room.room_id;
this._canonicalAlias = room.canonical_alias;
this._name = room.name;
this._mxcAvatarUrl = room.avatar_url;
this._homeserverUrlToPullMediaFrom = homeserverUrlToPullMediaFrom;
this._numJoinedMembers = room.num_joined_members;
this._topic = room.topic;

this._viaServers = viaServers;

this._blockedBySafeSearch = false;
}

get roomId() {
return this._roomId;
}

get canonicalAlias() {
return this._canonicalAlias;
}

get name() {
return this._name;
}

get mxcAvatarUrl() {
return this._mxcAvatarUrl;
}

get homeserverUrlToPullMediaFrom() {
return this._homeserverUrlToPullMediaFrom;
}

get numJoinedMembers() {
return this._numJoinedMembers;
}

get topic() {
return this._topic;
}

get archiveRoomUrl() {
return this._matrixPublicArchiveURLCreator.archiveUrlForRoom(
this._canonicalAlias || this._roomId,
{
// Only include via servers when we have to fallback to the room ID
viaServers: this._canonicalAlias ? undefined : this._viaServers,
}
);
}

get blockedBySafeSearch() {
return this._blockedBySafeSearch;
}

setBlockedBySafeSearch(blockedBySafeSearch) {
if (blockedBySafeSearch !== this._blockedBySafeSearch) {
this._blockedBySafeSearch = blockedBySafeSearch;
this.emitChange('blockedBySafeSearch');
}
}
}

module.exports = RoomCardViewModel;
Loading