Compare commits

...
Author SHA1 Message Date
Krishan 92727b60f4 Add desktop app link 2022-08-22 08:10:14 +05:30
Krishan e23ae8fec1 update intro 2022-08-21 21:53:36 +05:30
Krishan 93117be8cf Merge branch 'dev' into doc-update 2022-08-21 21:43:36 +05:30
Krishan 947c46ad83 Simplyfy readme and add various helpful links 2022-08-21 21:26:18 +05:30
Ajay Bura b3bff6b43f Edit last message with up arrow key (#774) 2022-08-21 19:41:48 +05:30
7 changed files with 112 additions and 46 deletions

No files matched your search

+6 -1
View File
@@ -36,4 +36,9 @@ It is not always possible to phrase every change in such a manner, but it is des
Also, we use [ESLint](https://eslint.org/) for clean and stylistically consistent code syntax, so make sure your pull request follow it.
**For any query or design discussion, join our [Matrix room](https://matrix.to/#/#cinny:matrix.org).**
**For any query or design discussion, join our [Matrix room](https://matrix.to/#/#cinny:matrix.org).**
## Helpful links
- [BEM methodology](http://getbem.com/introduction/)
- [Atomic design](https://bradfrost.com/blog/post/atomic-web-design/)
- [Matrix JavaScript SDK documentation](https://matrix-org.github.io/matrix-js-sdk/19.2.0/index.html)
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Ajay Bura (ajbura)
Copyright (c) 2021-present Ajay Bura (ajbura)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+29 -33
View File
@@ -1,9 +1,5 @@
<p align="center">
<img src="https://raw.githubusercontent.com/ajbura/cinny/dev/public/res/svg/cinny.svg?sanitize=true"
height="16">
<span><b>Cinny</b></span>
</p>
<p align="center">
# Cinny
<p>
<a href="https://github.com/ajbura/cinny/releases">
<img alt="GitHub release downloads" src="https://img.shields.io/github/downloads/ajbura/cinny/total?logo=github&style=social"></a>
<a href="https://hub.docker.com/r/ajbura/cinny">
@@ -16,21 +12,30 @@
<img alt="Sponsor Cinny" src="https://img.shields.io/opencollective/all/cinny?logo=opencollective&style=social"></a>
</p>
**Cinny** is a Matrix client focusing primarily on simple, elegant and secure interface. The main goal is to have a client that is easy on end user
and feels a modern chat application.
- [Contributing](./CONTRIBUTING.md)
A Matrix client focusing primarily on simple, elegant and secure interface. The main goal is to have an instant messaging application that is easy on people and has a modern touch.
- [Roadmap](https://github.com/ajbura/cinny/projects/11)
- [Contributing](./CONTRIBUTING.md)
## Building and Running
## Getting started
Web app is available at https://app.cinny.in and gets updated on each new release. The `dev` branch is continuously deployed at https://dev.cinny.in but keep in mind that it could have things broken.
### Running pre-compiled
You can also download our desktop app from [cinny-desktop repository](https://github.com/cinnyapp/cinny-desktop).
A tarball of pre-compiled version of the app is provided with each [release](https://github.com/ajbura/cinny/releases).
You can serve the application with a webserver of your choosing by simply copying `dist/` directory to the webroot.
To host Cinny on your own, download tarball of the app from [GitHub release](https://github.com/cinnyapp/cinny/releases/latest).
You can serve the application with a webserver of your choice by simply copying `dist/` directory to the webroot.
To set default Homeserver on login and register page, place a customized [`config.json`](config.json) in webroot of your choice.
Alternatively you can just pull the [DockerHub image](https://hub.docker.com/r/ajbura/cinny) by:
```
docker pull ajbura/cinny
```
or [ghcr image](https://github.com/cinnyapp/cinny/pkgs/container/cinny) by:
```
docker pull ghcr.io/cinnyapp/cinny:latest
```
<details>
<summary>PGP Public Key to verify pre-compiled tarball</summary>
<summary>PGP Public Key to verify tarball</summary>
```
-----BEGIN PGP PUBLIC KEY BLOCK-----
@@ -77,48 +82,39 @@ UeGsouhyuITLwEhScounZDqop+Dx
```
</details>
### Building from source
## Local development
> We recommend using a version manager as versions change very quickly. You will likely need to switch
between multiple Node.js versions based on the needs of different projects you're working on. [NVM on windows](https://github.com/coreybutler/nvm-windows#installation--upgrades) on Windows and [nvm](https://github.com/nvm-sh/nvm) on Linux/macOS are pretty good choices. Also recommended nodejs version is 16.15.0 LTS.
Execute the following commands to compile the app from its source code:
Execute the following commands to start a development server:
```sh
npm ci # Installs all dependencies
npm start # Serve a development version
```
To build the app:
```sh
npm run build # Compiles the app into the dist/ directory
```
You can then copy the files to a webserver's webroot of your choice.
To serve a development version of the app locally for testing, you need to use the command `npm start`.
### Running with Docker
This repository includes a Dockerfile, which builds the application from source and serves it with Nginx on port 80. To
use this locally, you can build the container like so:
```
docker build -t cinny:latest .
```
You can then run the container you've built with a command similar to this:
```
docker run -p 8080:80 cinny:latest
```
This will forward your `localhost` port 8080 to the container's port 80. You can visit the app in your browser by
navigating to `http://localhost:8080`.
This will forward your `localhost` port 8080 to the container's port 80. You can visit the app in your browser by navigating to `http://localhost:8080`.
Alternatively you can just pull the [DockerHub image](https://hub.docker.com/r/ajbura/cinny) by `docker pull ajbura/cinny`.
### Configuring default Homeserver
To set default Homeserver on login and register page, place a customized [`config.json`](config.json) in webroot of your choice.
## License
Copyright (c) 2021 Ajay Bura (ajbura)
Copyright (c) 2021-present Ajay Bura (ajbura)
Code licensed under the MIT License: <http://opensource.org/licenses/MIT>
+1 -1
View File
@@ -1,4 +1,4 @@
Graphics (c) by Ajay Bura (ajbura)
Copyright (c) 2021-present Ajay Bura (ajbura)
Graphic content is licensed under a
Creative Commons Attribution 4.0 International License.
+14 -8
View File
@@ -714,9 +714,9 @@ function getEditedBody(editedMEvent) {
}
function Message({
mEvent, isBodyOnly, roomTimeline, focus, fullTime,
mEvent, isBodyOnly, roomTimeline,
focus, fullTime, isEdit, setEdit, cancelEdit,
}) {
const [isEditing, setIsEditing] = useState(false);
const roomId = mEvent.getRoomId();
const { editedTimeline, reactionTimeline } = roomTimeline ?? {};
@@ -731,7 +731,7 @@ function Message({
const avatarSrc = mEvent.sender?.getAvatarUrl(initMatrix.matrixClient.baseUrl, 36, 36, 'crop') ?? null;
const edit = useCallback(() => {
setIsEditing(true);
setEdit(eventId);
}, []);
const reply = useCallback(() => {
replyTo(senderId, mEvent.getId(), body);
@@ -788,7 +788,7 @@ function Message({
eventId={mEvent.replyEventId}
/>
)}
{!isEditing && (
{!isEdit && (
<MessageBody
senderName={username}
isCustomHTML={isCustomHTML}
@@ -797,22 +797,22 @@ function Message({
isEdited={isEdited}
/>
)}
{isEditing && (
{isEdit && (
<MessageEdit
body={body}
onSave={(newBody) => {
if (newBody !== body) {
initMatrix.roomsInput.sendEditedMessage(roomId, mEvent, newBody);
}
setIsEditing(false);
cancelEdit();
}}
onCancel={() => setIsEditing(false)}
onCancel={cancelEdit}
/>
)}
{haveReactions && (
<MessageReactionGroup roomTimeline={roomTimeline} mEvent={mEvent} />
)}
{roomTimeline && !isEditing && (
{roomTimeline && !isEdit && (
<MessageOptions
roomTimeline={roomTimeline}
mEvent={mEvent}
@@ -829,6 +829,9 @@ Message.defaultProps = {
focus: false,
roomTimeline: null,
fullTime: false,
isEdit: false,
setEdit: null,
cancelEdit: null,
};
Message.propTypes = {
mEvent: PropTypes.shape({}).isRequired,
@@ -836,6 +839,9 @@ Message.propTypes = {
roomTimeline: PropTypes.shape({}),
focus: PropTypes.bool,
fullTime: PropTypes.bool,
isEdit: PropTypes.bool,
setEdit: PropTypes.func,
cancelEdit: PropTypes.func,
};
export { Message, MessageReply, PlaceholderMessage };
+2
View File
@@ -229,6 +229,8 @@
padding: var(--sp-extra-tight) 0;
&-btns button {
margin: var(--sp-tight) 0 0 0;
padding: var(--sp-ultra-tight) var(--sp-tight);
min-width: 0;
@include dir.side(margin, 0, var(--sp-tight));
}
}
+59 -2
View File
@@ -118,7 +118,15 @@ function handleOnClickCapture(e) {
}
}
function renderEvent(roomTimeline, mEvent, prevMEvent, isFocus = false) {
function renderEvent(
roomTimeline,
mEvent,
prevMEvent,
isFocus,
isEdit,
setEdit,
cancelEdit,
) {
const isBodyOnly = (prevMEvent !== null
&& prevMEvent.getSender() === mEvent.getSender()
&& prevMEvent.getType() !== 'm.room.member'
@@ -147,6 +155,9 @@ function renderEvent(roomTimeline, mEvent, prevMEvent, isFocus = false) {
roomTimeline={roomTimeline}
focus={isFocus}
fullTime={false}
isEdit={isEdit}
setEdit={setEdit}
cancelEdit={cancelEdit}
/>
);
}
@@ -386,6 +397,8 @@ function RoomViewContent({ eventId, roomTimeline }) {
const timelineSVRef = useRef(null);
const timelineScrollRef = useRef(null);
const eventLimitRef = useRef(null);
const [editEventId, setEditEventId] = useState(null);
const cancelEdit = () => setEditEventId(null);
const readUptoEvtStore = useStore(roomTimeline);
const [onLimitUpdate, forceUpdateLimit] = useForceUpdate();
@@ -470,6 +483,42 @@ function RoomViewContent({ eventId, roomTimeline }) {
}
}, [newEvent]);
const listenKeyboard = useCallback((event) => {
if (event.ctrlKey || event.altKey || event.metaKey) return;
if (event.key !== 'ArrowUp') return;
if (navigation.isRawModalVisible) return;
if (document.activeElement.id !== 'message-textarea') return;
if (document.activeElement.value !== '') return;
const {
timeline: tl, activeTimeline, liveTimeline, matrixClient: mx,
} = roomTimeline;
const limit = eventLimitRef.current;
if (activeTimeline !== liveTimeline) return;
if (tl.length > limit.length) return;
const mTypes = ['m.text'];
for (let i = tl.length - 1; i >= 0; i -= 1) {
const mE = tl[i];
if (
mE.getSender() === mx.getUserId()
&& mE.getType() === 'm.room.message'
&& mTypes.includes(mE.getContent()?.msgtype)
) {
setEditEventId(mE.getId());
return;
}
}
}, [roomTimeline]);
useEffect(() => {
document.body.addEventListener('keydown', listenKeyboard);
return () => {
document.body.removeEventListener('keydown', listenKeyboard);
};
}, [listenKeyboard]);
const handleTimelineScroll = (event) => {
const timelineScroll = timelineScrollRef.current;
if (!event.target) return;
@@ -535,7 +584,15 @@ function RoomViewContent({ eventId, roomTimeline }) {
const isFocus = focusId === mEvent.getId();
if (isFocus) jumpToItemIndex = itemCountIndex;
tl.push(renderEvent(roomTimeline, mEvent, isNewEvent ? null : prevMEvent, isFocus));
tl.push(renderEvent(
roomTimeline,
mEvent,
isNewEvent ? null : prevMEvent,
isFocus,
editEventId === mEvent.getId(),
setEditEventId,
cancelEdit,
));
itemCountIndex += 1;
}
if (roomTimeline.canPaginateForward() || limit.length < timeline.length) {