Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
613f9e1
BOARD IS THE BAN IN KANBAN YOU NOOB
fccview Apr 16, 2026
b17bd7b
feature: FreeBSD support
h-2 Apr 16, 2026
aa7e584
Add tzdata package to Dockerfile
sethgregory Apr 18, 2026
59887a1
Merge pull request #489 from sethgregory/develop
fccview Apr 18, 2026
2fa66f5
Potentially fix IOS scroll issue - cant test will need to ask some ni…
fccview Apr 18, 2026
69270ca
Merge branch 'develop' of github-fccview:fccview/jotty into develop
fccview Apr 18, 2026
c9f1b4d
edit on click for checklists and try to identify another potantial is…
fccview Apr 18, 2026
1be8f27
fix logo quality and date picker bug
fccview Apr 18, 2026
4080bc7
encryption bug fixes
fccview Apr 21, 2026
a29acae
semi-store encrypted password and fix bug on encryption create
fccview Apr 21, 2026
56d69d0
another effort to fix scrolling on ios
fccview Apr 21, 2026
1d8e76d
fix ios scroll, i tested on xcode, took forever to download ffs
fccview Apr 21, 2026
49e0a49
fix username on upload actions and table toolbar fixed in the wrong p…
fccview Apr 27, 2026
dbdb83f
add note editor fix for TOC
fccview Apr 27, 2026
e5063a0
add a patch system to sort out body size limit and future issues
fccview Apr 27, 2026
70e7322
Merge remote-tracking branch 'public' into fbsd2
fccview Apr 27, 2026
bea1498
Merge remote-tracking branch 'public/develop' into fbsd2
fccview Apr 27, 2026
31a05de
change this to work with the new patching system instead
fccview Apr 27, 2026
4bf22df
add global setting for date/time format
fccview Apr 27, 2026
8c55b2f
Merge pull request #488 from h-2/fbsd2
fccview Apr 28, 2026
3a16a8c
bump package
fccview Apr 28, 2026
6bfc453
Merge branch 'develop' of github-fccview:fccview/jotty into develop
fccview Apr 28, 2026
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
8 changes: 6 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN apk add --no-cache su-exec git grep sed
RUN apk add --no-cache su-exec git grep sed tzdata

RUN if ! getent group 1000 > /dev/null 2>&1; then \
addgroup --system --gid 1000 appgroup; \
Expand All @@ -51,6 +51,10 @@ COPY --from=builder /app/public ./public

COPY --from=builder /app/howto ./howto

COPY --from=builder /app/scripts/apply-patches.js ./scripts/apply-patches.js
COPY --from=builder /app/patches ./patches
RUN mkdir -p /app/user_patches && chown -R 1000:1000 /app/scripts /app/patches /app/user_patches

COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

Expand All @@ -60,4 +64,4 @@ ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD ["node", "server.js"]
CMD ["node", "server.js"]
35 changes: 35 additions & 0 deletions app/_components/FeatureComponents/Admin/Parts/AppSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,41 @@ export const AppSettingsTab = () => {
</span>
</span>
</div>
<div>
<Label htmlFor="defaultDateFormat" className="block mb-3">
{t("admin.defaultDateFormat")}
</Label>
<Dropdown
value={settings?.defaultDateFormat || "dd/mm/yyyy"}
onChange={(value) => handleInputChange("defaultDateFormat", value)}
options={[
{ id: "dd/mm/yyyy", name: "DD/MM/YYYY" },
{ id: "mm/dd/yyyy", name: "MM/DD/YYYY" },
{ id: "yyyy/mm/dd", name: "YYYY/MM/DD" },
]}
disabled={!isSuperAdmin}
/>
<span className="text-md lg:text-xs text-muted-foreground">
{t("admin.defaultDateFormatDescription")}
</span>
</div>
<div>
<Label htmlFor="defaultTimeFormat" className="block mb-3">
{t("admin.defaultTimeFormat")}
</Label>
<Dropdown
value={settings?.defaultTimeFormat || "12-hours"}
onChange={(value) => handleInputChange("defaultTimeFormat", value)}
options={[
{ id: "12-hours", name: t("settings.hours12") },
{ id: "24-hours", name: t("settings.hours24") },
]}
disabled={!isSuperAdmin}
/>
<span className="text-md lg:text-xs text-muted-foreground">
{t("admin.defaultTimeFormatDescription")}
</span>
</div>
<div>
<Label htmlFor="hideLanguageSelector" className="block mb-3">
{t("admin.hideLanguageSelector")}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,13 @@ const NestedChecklistItemComponent = ({
className={cn(
"relative my-1",
hasChildren &&
!isChild &&
"border-l-2 bg-muted/30 border-l-primary/70 rounded-jotty border-dashed border-t",
!isChild &&
"border-l-2 bg-muted/30 border-l-primary/70 rounded-jotty border-dashed border-t",
!hasChildren &&
!isChild &&
"border-l-2 bg-muted/30 border-l-primary/70 rounded-jotty border-dashed border-t",
!isChild &&
"border-l-2 bg-muted/30 border-l-primary/70 rounded-jotty border-dashed border-t",
isChild &&
"ml-4 rounded-jotty border-dashed border-l border-border border-l-primary/70",
"ml-4 rounded-jotty border-dashed border-l border-border border-l-primary/70",
"first:mt-0 transition-colors duration-150",
isActive && "bg-muted/20",
isDragging && "opacity-50 z-50",
Expand All @@ -352,7 +352,7 @@ const NestedChecklistItemComponent = ({
isChild ? "px-2.5 py-1.5 lg:py-2" : "p-1.5 lg:p-2",
completed && "opacity-80",
!permissions?.canEdit &&
"opacity-50 cursor-not-allowed pointer-events-none",
"opacity-50 cursor-not-allowed pointer-events-none",
)}
>
{!isPublicView && !isDragDisabled && permissions?.canEdit && (
Expand Down Expand Up @@ -434,7 +434,7 @@ const NestedChecklistItemComponent = ({
)}
</div>
) : (
<div className="flex-1 flex items-center justify-between gap-2 max-w-[85%] lg:max-w-full">
<div className="flex-1 flex items-center justify-between gap-2 min-w-0">
<div className="flex-1 flex gap-1.5 max-w-full">
<label
htmlFor={item.id}
Expand All @@ -459,10 +459,47 @@ const NestedChecklistItemComponent = ({
<RecurrenceIndicator recurrence={item.recurrence} />
)}

<span className="break-words max-w-[85%] lg:max-w-full">
{tagsEnabled ? renderTextWithHashtags(displayText) : displayText}
</span>
{!(
user?.checklistItemClickAction === "edit" &&
permissions?.canEdit &&
onEdit &&
!isPublicView
) && (
<span className="break-words min-w-0">
{tagsEnabled ? renderTextWithHashtags(displayText) : displayText}
</span>
)}
</label>
{user?.checklistItemClickAction === "edit" &&
permissions?.canEdit &&
onEdit &&
!isPublicView && (
<span
role="button"
tabIndex={0}
onClick={(e) => {
if (e.metaKey || e.ctrlKey) {
onToggle(item.id, !(item.completed || completed));
return;
}
handleEdit();
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
handleEdit();
}
}}
className={cn(
"text-md lg:text-sm transition-all duration-200 cursor-text break-words min-w-0 flex items-center select-text",
item.completed || completed
? "line-through text-muted-foreground"
: "text-foreground",
)}
>
{tagsEnabled ? renderTextWithHashtags(displayText) : displayText}
</span>
)}
</div>

<LastModifiedCreatedInfo
Expand Down Expand Up @@ -651,9 +688,8 @@ const NestedChecklistItemComponent = ({
<div className={cn("pt-1")}>
{draggedItemId !== item.id && (
<DropIndicator
id={`drop-before-child::${
item.children![0]?.id || `${item.id}-start`
}`}
id={`drop-before-child::${item.children![0]?.id || `${item.id}-start`
}`}
data={{
type: "drop-indicator",
position: "before",
Expand Down
134 changes: 66 additions & 68 deletions app/_components/FeatureComponents/Howto/HowtoSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,86 +7,84 @@ import { useNavigationGuard } from "@/app/_providers/NavigationGuardProvider";
import { useTranslations } from "next-intl";
import { getHowtoGuides } from "@/app/_utils/howto-utils";
import {
HelpCircleIcon,
SquareLock01Icon,
SmartPhone01Icon,
PaintBrush04Icon,
LaptopProgrammingIcon,
LockKeyIcon,
TranslationIcon,
ComputerPhoneSyncIcon,
ZapIcon,
GridIcon,
CodeIcon,
RainIcon
HelpCircleIcon,
SquareLock01Icon,
SmartPhone01Icon,
PaintBrush04Icon,
LaptopProgrammingIcon,
LockKeyIcon,
TranslationIcon,
ComputerPhoneSyncIcon,
ZapIcon,
GridIcon,
CodeIcon,
RainIcon,
Wrench01Icon,
} from "hugeicons-react";

interface HowtoSidebarProps {
isOpen: boolean;
onClose: () => void;
isOpen: boolean;
onClose: () => void;
}

const iconMap: Record<string, any> = {
zap: ZapIcon,
hash: GridIcon,
code: CodeIcon,
paintbrush: PaintBrush04Icon,
laptop: LaptopProgrammingIcon,
key: LockKeyIcon,
computerphone: ComputerPhoneSyncIcon,
smartphone: SmartPhone01Icon,
lock: LockKeyIcon,
squarelock: SquareLock01Icon,
translation: TranslationIcon,
rain: RainIcon,
zap: ZapIcon,
hash: GridIcon,
code: CodeIcon,
paintbrush: PaintBrush04Icon,
laptop: LaptopProgrammingIcon,
key: LockKeyIcon,
computerphone: ComputerPhoneSyncIcon,
smartphone: SmartPhone01Icon,
lock: LockKeyIcon,
squarelock: SquareLock01Icon,
translation: TranslationIcon,
rain: RainIcon,
patch: Wrench01Icon,
};

export const HowtoSidebar = ({ isOpen, onClose }: HowtoSidebarProps) => {
const t = useTranslations();
const pathname = usePathname();
const router = useRouter();
const { checkNavigation } = useNavigationGuard();
const t = useTranslations();
const pathname = usePathname();
const router = useRouter();
const { checkNavigation } = useNavigationGuard();

const guides = getHowtoGuides(t);
const guides = getHowtoGuides(t);

const handleNavigate = (path: string) => {
checkNavigation(() => {
router.push(path);
if (window.innerWidth < 1024) {
onClose();
}
});
};
const handleNavigate = (path: string) => {
checkNavigation(() => {
router.push(path);
if (window.innerWidth < 1024) {
onClose();
}
});
};

const isItemActive = (path: string) => {
return pathname === path;
};
const isItemActive = (path: string) => {
return pathname === path;
};

return (
<SidebarWrapper
isOpen={isOpen}
onClose={onClose}
title={t("help.howTo")}
>
<div className="space-y-1">
<div className="space-y-0.5 pl-2">
{guides.map((guide) => {
const Icon = iconMap[guide.icon] || HelpCircleIcon;
const isActive = isItemActive(`/howto/${guide.id}`);
return (
<SidebarWrapper isOpen={isOpen} onClose={onClose} title={t("help.howTo")}>
<div className="space-y-1">
<div className="space-y-0.5 pl-2">
{guides.map((guide) => {
const Icon = iconMap[guide.icon] || HelpCircleIcon;
const isActive = isItemActive(`/howto/${guide.id}`);

return (
<SidebarItem
href={`/howto/${guide.id}`}
key={guide.id}
icon={Icon}
label={guide.name}
isActive={isActive}
onClick={() => handleNavigate(`/howto/${guide.id}`)}
/>
);
})}
</div>
</div>
</SidebarWrapper>
);
return (
<SidebarItem
href={`/howto/${guide.id}`}
key={guide.id}
icon={Icon}
label={guide.name}
isActive={isActive}
onClick={() => handleNavigate(`/howto/${guide.id}`)}
/>
);
})}
</div>
</div>
</SidebarWrapper>
);
};
2 changes: 1 addition & 1 deletion app/_components/FeatureComponents/Notes/NoteClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const NoteClient = ({ note, categories }: NoteClientProps) => {
<SwipeNavigationWrapper
noteId={localNote.id}
noteCategory={localNote.category}
enabled={!viewModel.isEditing}
enabled={!viewModel.isEditMode}
>
<NoteEditor
note={localNote}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { TableOfContents } from "../TableOfContents";
import { useSearchParams } from "next/navigation";
import { usePermissions } from "@/app/_providers/PermissionsProvider";
import { useNotesStore } from "@/app/_utils/notes-store";
import { useAppMode } from "@/app/_providers/AppModeProvider";

export interface NoteEditorProps {
note: Note;
Expand All @@ -31,6 +32,12 @@ export const NoteEditor = ({
const { showTOC, setShowTOC } = useNotesStore();
const decryptModalRef = useRef<(() => void) | null>(null);
const viewModalRef = useRef<(() => void) | null>(null);
const { user } = useAppMode();
const searchParams = useSearchParams();
const _isEditMode =
viewModel.isEditing ||
user?.notesDefaultMode === "edit" ||
searchParams?.get("editor") === "true";

return (
<div className="flex-1 flex flex-col overflow-hidden bg-background h-full">
Expand All @@ -47,8 +54,8 @@ export const NoteEditor = ({
onOpenViewModal={viewModalRef}
/>

<div className="flex h-full w-full relative">
<div className="flex-1 overflow-y-auto jotty-scrollable-content max-h-[95vh]">
<div className="flex flex-1 w-full relative min-h-0">
<div className="flex-1 overflow-y-auto jotty-scrollable-content min-h-0">
<NoteEditorContent
isEditing={viewModel.isEditing}
noteContent={note.content}
Expand All @@ -67,11 +74,11 @@ export const NoteEditor = ({
<div className="w-64 border-l border-border">
<TableOfContents
content={
viewModel.isEditing
_isEditMode
? viewModel.derivedMarkdownContent
: note.content || ""
}
isEditing={viewModel.isEditing}
isEditing={_isEditMode}
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,8 @@ export const NoteEditorContent = ({
<>
<ReadingProgressBar />
<div
className={`px-6 pt-6 pb-24 ${
compactMode ? "max-w-[900px] mx-auto" : ""
}`}
className={`px-6 pt-6 pb-4 ${compactMode ? "max-w-[900px] mx-auto" : ""
}`}
>
<UnifiedMarkdownRenderer
content={encrypted ? editorContent : noteContent || ""}
Expand Down
Loading
Loading